zoukankan      html  css  js  c++  java
  • Quartz入门

    一、Quartz介绍

    直接看官网吧,Quartz官网

    什么是 Quartz Job Scheduling Library?

    Quartz是一个功能丰富的开源任务调度库,几乎可以集成在任何Java应用程序中 - 从最小的独立应用程序到最大的电子商务系统。Quartz可用于创建简单或复杂的计划,以执行数十,数百甚至数万个任务; 将任务定义为标准Java组件的任务,这些组件可以执行几乎任何可以编程的程序。Quartz Scheduler包含许多企业级功能,例如支持JTA事务和集群。

    下载地址:http://www.quartz-scheduler.org/downloads/

    官网终最新已经是version:2.4.0的版本了,另外需要提醒的是1.x和2.x的版本差别挺大的,学习和使用主要是使用2.x的版本

    我们选择2.4.0的版本进行下载,我们主要是用其Jar包

    第一个c3p0的依赖,是个数据库连接池,本次案例用不上。

    二、Quartz案例

    使用idea新建一个普通的java工程即可,做一个简单的案例,这里就是孤单的使用Quartz,没有与Spring做整合。

    直接上代码:

    package com.helius.job;
    
    import com.helius.service.MeetingService;
    import org.quartz.*;
    
    import java.util.List;
    
    /**
     * @Author Helius
     * @Create 2019-08-18-20:48
     */
    public class PlanJob implements Job {
        MeetingService meetingService = new MeetingService();
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();// 这个其实就是TestQuartz类的withIdentity方法中定义的属性
            JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
            System.out.println(triggerKey + "	" + jobKey);//这句对应控制台输出的group1.meeting trigger	group1.meeting job
    
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
            List infos = (List) jobDataMap.get("infos");
            System.out.println(infos);
    
            // 存放计划执行的任务
            meetingService.calClassMeeting();
    
        }
    }
    
    
    package com.helius.service;
    
    /** * @Author Helius
     * @Create 2019-08-18-20:46
     */
    // 这个为我们具体要执行的任务
    public class MeetingService {
        public void calClassMeeting() {
            System.out.println("需要提醒的任务(召开会议.....)");
    
        }
    
    }
    
    
    package com.helius.test;
    
    import com.helius.job.PlanJob;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    
    import java.text.ParseException;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @Author Helius
     * @Create 2019-08-18-20:51
     */
    public class TestQuartz {
        public static void main(String[] args) throws SchedulerException, InterruptedException, ParseException {
    //        PlanJob
            JobBuilder jobBuilder = JobBuilder.newJob(PlanJob.class);
            // 产生实际使用的Job
            JobDetail jobDetail = jobBuilder.withIdentity("meeting job", "group1").build();
    
            // 向Job的execute()中传入一些参数
            JobDataMap jobDataMap = jobDetail.getJobDataMap();
            List<String> names = Arrays.asList(new String[]{"zs","ls","ww"});
            jobDataMap.put("infos",names);
    
    		// 下面这几句关于TriggerBuilder可以采用方法链的写法更简洁,因为返回的是当前对象this
            // 触发器:时间规则,,依赖两个对象(TriggerBuilder,Scheduel)
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            triggerBuilder = triggerBuilder.withIdentity("meeting trigger", "group1");
            triggerBuilder.startNow();//当满足条件时执行
    
    /*        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date start = sdf.parse("2019-8-18 21:20:45");
            Date end = sdf.parse("2019-8-18 21:20:55");
            triggerBuilder.startAt(start);
            triggerBuilder.endAt(end);*/
    
            //ScheduleBuilder:定执行的周期
            SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
            scheduleBuilder.withIntervalInSeconds(1);// 每隔一秒执行一次
            scheduleBuilder.withRepeatCount(2);//执行2次
            // 产生触发器
            SimpleTrigger trigger = triggerBuilder.withSchedule(scheduleBuilder).build();
    
    
    
            // 调度器(工厂产生调度器)
            SchedulerFactory schedulerFactory = new  StdSchedulerFactory();
            // 产生调度器
            Scheduler scheduler = schedulerFactory.getScheduler();
            // 产生一个默认的调度器,与上面两句代码等价
            //Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();
            
            // 通过调度器 将  任务  和 触发器 一一对应
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start();
    
            Thread.sleep(10000); // 休眠10秒,保证关闭前代码任务执行完了
            // 关闭方法
            scheduler.shutdown(); // 如果不shutdown,应用不会停止,因为还有活动的线程
        }
    }
    
    

    打印下结果

    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    

    就是这么简单,先把代码跑起来,再来具体学习。

    先看PlanJob类,实现了Job类,这是Quartz中的类,表示这是一任务,实现这个Job唯一的抽象方法execute,当我们看示例代码时,我们可以只关注 meetingService.calClassMeeting();这一句任务的执行代码即可,

    方法execute有一个参数:JobExecutionContext jobExecutionContext即Job执行的上下文对象,当然听这个名字,就能知道通过这个对象,我们能拿到很多我们可能在任务执行的时候需要的信息。


    考虑这样一个需求,我们的任务是提醒开会,那提醒哪些人需要开会呢,好像在打印的过程中,我们输出了

    [zs, ls, ww]

    这样一行信息,我们怎么加进去呢,

    TestQuartz类中有这样的代码

            // 向Job的execute()中传入一些参数
            JobDataMap jobDataMap = jobDetail.getJobDataMap();
            List<String> names = Arrays.asList(new String[]{"zs","ls","ww"});
            jobDataMap.put("infos",names);
    

    然后我们在PlanJob中可以动态的拿到这些信息

            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
            List infos = (List) jobDataMap.get("infos");
            System.out.println(infos);
    

    其实还有另外一种写法,通过usingJobData这个方法,这里采用了链式写法, 建议自己写一下。

              //定义一个JobDetail
                JobDetail job = newJob(MailJob.class) //指定干活的类MailJob
                    .withIdentity("mailjob1", "mailgroup") //定义任务名称和分组
                    .usingJobData("email", "admin@10086.com") //定义属性
                    .build();
    

    再来看PlanJob类中的

            TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
            JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
            System.out.println(triggerKey + "	" + jobKey);
    

    这个就对印我们输出行中的,毕竟任务可能有很多,所以我们需要给他们分个组,加个id,即加个唯一标志符。

    group1.meeting trigger	group1.meeting job
    

    剩下的一些代码,在注释里面已经写的很详细了,不再细讲了

    三、Quartz的异步

    Quartz有这样一个特性,就是在第一个任务未执行完,第二个任务便会继续开始,我们来测试下,我们改写一下PlanJob类,

    public class PlanJob implements Job {
        MeetingService meetingService = new MeetingService();
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
            JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
            System.out.println(triggerKey + "	" + jobKey);
    
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
            List infos = (List) jobDataMap.get("infos");
            System.out.println(infos);
    
            // 存放计划执行的任务
            meetingService.calClassMeeting();
            try {
                Thread.sleep(5000);  // 休眠5秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行完了");
        }
    }
    

    观察控制台:

    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    执行完了
    执行完了
    执行完了
    

    在第一个任务执行后,中途会有5秒的休眠时间,但是第二个任务依旧开始了

    默认的情况下,无论上一次任务是否结束或者完成,只要规定的时间到了,那么下一次就开始。

    有时候会做长时间的任务,比如数据库备份,这个时候就希望上一次备份成功结束之后,才开始下一次备份,即便是规定时间到了,也不能开始,因为这样很有可能造成 数据库被锁死 (几个线程同时备份数据库,引发无法预计的混乱)。

    那么在这种情况下,给数据库备份任务增加一个注解就好了: @DisallowConcurrentExecution

    给PlanJob类加上注解后,

    再次运行TestQuartz类,观察控制台输出结果:

    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    执行完了
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    执行完了
    group1.meeting trigger	group1.meeting job
    [zs, ls, ww]
    需要提醒的任务(召开会议.....)
    执行完了
    

    和我们预计的一样。
    Tips:Quartz的官网的文档很详细,例子也很多,英文也使用的很简单,值得详细阅读。
    好像还有很多没讲完,睡觉睡觉,加油加油!!!

    你所看得到的天才不过是在你看不到的时候还在努力罢了!
  • 相关阅读:
    C#中的多态
    反编译工具
    富文本粘贴图片
    [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
    Silverlight在IIS中的配置
    HubbleDotNet开源全文搜索数据库项目技术详解
    Thank you for choosing Telerik RadRichTextBox
    Asp.net读取AD域信息的方法<转>
    Sharepoint学习笔记—ECMAScript对象模型系列1、ECMAScript对象模型的引入
    SharePoint WebService
  • 原文地址:https://www.cnblogs.com/heliusKing/p/11374520.html
Copyright © 2011-2022 走看看