Quartz深入浅出

  1. 什么是Quartz
    1. Quartz是一个开源的作业调度框架,由java编写,在.NET平台为Quartz.Net,通过Quart可以快速完成任务调度的工作.
  2. Quartz能干什么/应用场景
    1. 如网页游戏中挂机自动修炼如8个小时,人物相关数值进行成长,当使用某道具后,时间减少到4个小时,人物对应获得成长值.这其中就涉及到了Scheduler的操作,定时对人物进行更新属性操作,更改定时任务执行时间.
    2. 网页游戏中会大量涉及到Scheduler的操作,有兴趣的朋友可自行联想.
    3. 企业中如每天凌晨2点触发数据同步、发送Email等操作
  3. 同类框架对比
    1. TimeTask TimeTask在Quartz前还是显得过于简单、不完善,不能直接满足开发者的较为复杂的应用场景.
  4. 资源
    1. 官网:http://www.quartz-scheduler.org/
    2. 下载:http://www.quartz-scheduler.org/downloads
    3. maven pom
      1. <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>
    4. 源代码 svn:http://svn.terracotta.org/svn/quartz
    5. 本文章采用的是2.21版本:CSDN下载:http://download.csdn.net/detail/chenweitang123/7636703
    6. 例子Demo:CSDN下载:整理完后上传.
  5. 框架分析
    1. 接口
    2. 类图
  6. Quartz中的设计模式
    1. Builder模式
      1. 所有关键组件都有Builder模式来构建  <Builder> 如:JobBuilder、TriggerBuilder
    2. Factory模式
      1. 最终由Scheduler的来进行组合各种组件  <Factory> 如SchedulerFactory
    3. Quartz项目中大量使用组件模式,插件式设计,可插拔,耦合性低,易扩展,开发者可自行定义自己的Job、Trigger等组件
    4. 链式写法,Quartz中大量使用链式写法,与jQuery的写法有几分相似,实现也比较简单,如:
      1.  $(this).addClass("divCurrColor").next(".divContent").css("display","block");  
      2. newTrigger().withIdentity( "trigger3""group1").startAt( startTime)
                .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10)).build();
  7. 框架核心分析
    1. SchedulerFactory    -- 调度程序工厂
      1. StdSchedulerFactory   -- Quartz默认的SchedulerFactory
      2. DirectSchedulerFactory  --   DirectSchedulerFactory是对SchedulerFactory的直接实现,通过它可以直接构建Scheduler、threadpool 
        1. ThreadExecutor / DefaultThreadExecutor   -- 内部线程操作对象
    2. JobExecutionContext -- JOB上下文,保存着Trigger、 JobDeaitl 等信息,JOB的execute方法传递的参数就是对象的实例
      1. JobExecutionContextImpl
    3. Scheduler    -- 调度器
      1. StdScheduler    -- Quartz默认的Scheduler
      2. RemoteScheduler  -- 带有RMI功能的Scheduler
    4. JOB --任务对象
      1. JobDetail  -- 他是实现轮询的一个的回调类,可将参数封装成JobDataMap对象,Quartz将任务的作业状态保存在JobDetail中.
      2. JobDataMap --  JobDataMap用来报错由JobDetail传递过来的任务实例对象
    5. Trigger
      1. SimpleTrigger <普通的Trigger> --  SimpleScheduleBuilder
      2. CronTrigger  <带Cron Like 表达式的Trigger> -- CronScheduleBuilder
      3. CalendarIntervalTrigger <带日期触发的Trigger> -- CalendarIntervalScheduleBuilder
      4. DailyTimeIntervalTrigger <按天触发的Trigger> -- DailyTimeIntervalScheduleBuilder
    6. ThreadPool  --  为Quartz运行任务时提供了一些线程
      1. SimpleThreadPool  --一个Quartz默认实现的简单线程池,它足够健壮,能够应对大部分常用场景
    7. -----以上是Quartz涉及到的一些关键对象,详细的内容如有机会会在后续的文章中展开!
  8. Quartz类图

    1. 类图中主要分为5块:Factory、Bulider、Scheduler、Trigger、JOB
  9. 思想
    1. [java]  view plain  copy
      1. // 1、工厂模式 构建Scheduler的Factory,其中STD为Quartz默认的Factory  
      2. //    开发者亦可自行实现自己的Factory;Job、Trigger等组件  
      3. SchedulerFactory sf = new StdSchedulerFactory();  
      4.   
      5. // 2、通过SchedulerFactory构建Scheduler对象  
      6. Scheduler sched = sf.getScheduler();  
      7.   
      8. // 3、org.quartz.DateBuilder.evenMinuteDate  -- 通过DateBuilder构建Date  
      9. Date runTime = evenMinuteDate( new Date());  
      10.   
      11. // 4、org.quartz.JobBuilder.newJob <下一分钟> --通过JobBuilder构建Job  
      12. JobDetail job = newJob(HelloJob.class).withIdentity("job1","group1").build();  
      13.   
      14. // 5、通过TriggerBuilder进行构建Trigger  
      15. Trigger trigger = newTrigger().withIdentity("trigger1","group1")  
      16.             .startAt(runTime).build();  
      17.   
      18. // 6、工厂模式,组装各个组件<JOB,Trigger>  
      19. sched.scheduleJob (job, trigger);  
      20.   
      21. // 7、start   
      22. sched.start();  
      23.   
      24. try {  
      25.   Thread.sleep(65L * 1000L);  
      26. catch (Exception e) {  
      27. }  
      28.   
      29. // 8、通过Scheduler销毁内置的Trigger和Job  
      30. sched.shutdown(true);  
  10. 一句话看懂Quartz
    1.    1、创建调度工厂();    //工厂模式
         2、根据工厂取得调度器实例();   //工厂模式
         3、Builder模式构建子组件<Job,Trigger>  // builder模式, 如JobBuilder、TriggerBuilder、DateBuilder
         4、通过调度器组装子组件   调度器.组装<子组件1, 子组件2... >  //工厂模式

         5、调度器.start(); //工厂模式


Hello Quartz / 本文通过一个简单的例子让大家快速了解Quartz,上手,并了解Quartz内的一些关键对象 如 Scheduler、Job、Trigger、JobExecutionContext等对象
  1. 导入Quartz所需的两个jar包 <quartz-2.2.1.jarr、quartz-jobs-2.2.1.jar>
    1. 创建我们自己的Job类 HelloJob,进行简单的输出
    2. [java]  view plain  copy
      1. package org.quartz.examples.examples01;  
      2.   
      3. import java.util.Date;  
      4. import org.slf4j.Logger;  
      5. import org.slf4j.LoggerFactory;  
      6. import org.quartz.Job;  
      7. import org.quartz.JobExecutionContext;  
      8. import org.quartz.JobExecutionException;  
      9.   
      10. /** 
      11.  * hello world Quartz 
      12.  * @author weeks 
      13.  * 
      14.  */  
      15. public class HelloJob implements Job {  
      16.   
      17.     private static Logger _log = LoggerFactory.getLogger(HelloJob .class );  
      18.   
      19.     /** 
      20.      * Job,Job需要一个公有的构造函数,否则Factory无法构建 
      21.      */  
      22.     public HelloJob() {  
      23.     }  
      24.   
      25.     /** 
      26.      * 实现execute方法 
      27.      */  
      28.     public void execute(JobExecutionContext context)  
      29.         throws JobExecutionException {  
      30.         _log.info( "Hello World! - " + new Date());  
      31.     }  
      32.   
      33. }  
    3. 创建我们的Job运行例子,在下一分钟执行我们自己Job
    4. [java]  view plain  copy
      1. package org.quartz.examples.examples01;  
      2.   
      3. import static org.quartz.DateBuilder.evenMinuteDate ;  
      4. import static org.quartz.JobBuilder.newJob ;  
      5. import static org.quartz.TriggerBuilder.newTrigger ;  
      6. import org.quartz.JobDetail;  
      7. import org.quartz.Scheduler;  
      8. import org.quartz.SchedulerFactory;  
      9. import org.quartz.Trigger;  
      10. import org.quartz.impl.StdSchedulerFactory;  
      11. import org.slf4j.Logger;  
      12. import org.slf4j.LoggerFactory;  
      13. import java.util.Date;  
      14.   
      15. /** 
      16.  * 此Demo将演示如何启动和关闭Quartz调度器,以及如何运作 
      17.  * @author weeks 
      18.  * 
      19.  */  
      20. public class SimpleExample {  
      21.   
      22.   public void run() throws Exception {  
      23.     Logger log = LoggerFactory.getLogger(SimpleExample.class);  
      24.   
      25.     log.info("------- Initializing ----------------------");  
      26.   
      27.     // 1、工厂模式 构建Scheduler的Factory,其中STD为Quartz默认的Factory,开发者亦可自行实现自己的Factory;Job、Trigger等组件  
      28.     SchedulerFactory sf = new StdSchedulerFactory();  
      29.     // 2、通过SchedulerFactory获得Scheduler对象  
      30.     Scheduler sched = sf.getScheduler();  
      31.   
      32.     log.info("------- Initialization Complete -----------");  
      33.   
      34.     // 3、org.quartz.DateBuilder.evenMinuteDate <下一分钟>  -- 通过DateBuilder构建Date  
      35.     Date runTime = evenMinuteDate(new Date());  
      36.   
      37.     log.info("------- Scheduling Job  -------------------");  
      38.   
      39.     // 4、org.quartz.JobBuilder.newJob --通过JobBuilder构建Job  
      40.     JobDetail job = newJob(HelloJob.class).withIdentity("job1""group1").build();  
      41.   
      42.     // 5、通过TriggerBuilder进行构建  
      43.     Trigger trigger = newTrigger().withIdentity("trigger1" , "group1").startAt(runTime ).build();  
      44.   
      45.     // 6、工厂模式,组装各个组件<JOB,Trigger>  
      46.     sched.scheduleJob(job, trigger);  
      47.      
      48.     // [group1.job1] will run at:  
      49.     log.info(job.getKey() + " will run at: " + runTime);  
      50.   
      51.     // 7、start  
      52.     sched.start();  
      53.   
      54.     log.info("------- Started Scheduler -----------------");  
      55.   
      56.     log.info("------- Waiting 65 seconds... -------------");  
      57.     try {  
      58.       // wait 65 seconds to show job  
      59.       Thread.sleep(65L * 1000L);  
      60.       // executing...  
      61.     } catch (Exception e) {  
      62.       //  
      63.     }  
      64.   
      65.     // shut down the scheduler  
      66.     log.info("------- Shutting Down ---------------------");  
      67.     // 8、通过Scheduler销毁内置的Trigger和Job  
      68.     sched.shutdown(true);  
      69.     log.info("------- Shutdown Complete -----------------");  
      70.   }  
      71.   
      72.   public static void main(String[] args) throws Exception {  
      73.   
      74.     SimpleExample example = new SimpleExample();  
      75.     example.run();  
      76.   
      77.   }  
      78.   
      79. }  
  2. 让我们来看看上面的代码究竟做了些什么:
    1. 创建一个Quartz Job类,必须实现 org.quartz.Job ,这个接口只有一个你要实现的方法,execute方法,其中execute的接口定义如下  
      1.   void execute(JobExecutionContext  context throws JobExecutionException;
      2.   当Quartz调度器到约定的时间,它就会生成一个Job的实例,所以你实现Job接口 必须提供一个公有函数,否则会抛出异常,并调用execute方法.其中调度器只管执行,而不关心结果,除非抛出JobExecutionException异常.
      3.  JobExecutionContext 中封装有Quartz运行所需要的所有信息,可以参见下面具体的代码片段.
    2. 其中涉及到的Scheduler、Job、Trigger 3个关键对象  (后续会专门介绍这3个对象)
      1. 其中Scheduler调度器对象,它的方法有start()、shutdown()等方法,负责管理整个调度作业.
      2. Job 又与几个对象有关 Job、JobDetail、JobDataMap
        1. 通过类图来看他们之间的关系

        2. 通过类图可以很明显的看出由JobExecutionContext来组装各个子组件,我们看看JobExecutionContextImpl的源代码,它保存着所有上下文信息
        3. [java]  view plain  copy
          1. private transient Scheduler scheduler ;  
          2.   
          3. private Trigger trigger;  
          4.   
          5. private JobDetail jobDetail;  
          6.   
          7. private JobDataMap jobDataMap;  
          8.   
          9. private transient Job job;  
          10.   
          11. private Calendar calendar;  
          12.   
          13. private boolean recovering = false;  
          14.   
          15. private int numRefires = 0;  
          16.   
          17. private Date fireTime;  
          18.   
          19. private Date scheduledFireTime;  
          20.   
          21. private Date prevFireTime;  
          22.   
          23. private Date nextFireTime;  
          24.   
          25. private long jobRunTime = -1;  
          26.   
          27. private Object result;  
          28.   
          29. private HashMap<Object, Object> data=new HashMap<Object, Object>();  
        4. 关于JobDetail
          1. JobDetail不存储具体的实例,但它允许你定义一个实例,JobDetail 又指向JobDataMap
          2. JobDetail持有Job的详细信息,如它所属的组,名称等信息
        5. 关于JobDataMap
          1. JobDataMap保存着任务实例的对象,并保持着他们状态信息,它是Map接口的实现,即你可以往里面put和get一些你想存储和获取的信息.
      3. 关于Trigger
        1. 即根据具体约定的触发器,具体的如:SimpleTrigger、CronTrigger 等