阅读目录

简单介绍

在实际编程中,我们经常会遇到定时任务,或是隔一段时间执行指定任务,例如:
1. 在每月的30号9:00统计人员出勤情况;
2. 每隔10分钟执行一次入库操作;
上面的例子中,需要执行的操作就是Job(作业),而在指定时间或者间隔固定时间去触发这个Job的就是Trigger(触发器),而把二者联系在一起的就是Scheduler(调度器);

Quartz主要要理解三个方面:
  1. Scheduler:调度器,将Job和Trigger关联起来;
  2. Job          :需要执行的作业;
  3. Trigger    :触发器,指定执行的时间,主要包括两种方式:
<1>指定时间:如每月15号9:00,或者每天的12:00等等;
<2>间隔时间:如每隔10分钟执行一次,每隔2h执行一次等等;

一、Quartz简单实例

下面给出一个简单的示例:
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
 
  Scheduler sched = schedFact.getScheduler();
 
  sched.start();
 
  // define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1")
      .build();
 
  // Trigger the job to run now, and then every 40 seconds
  trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())
      .build();
 
  // Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);
下面的截图是Java源码给出的示例:


我们在使用Quartz时,一般的操作步骤为:
步骤1:自定义Job类(如:MyJob),实现Job接口;
步骤2:使用JobBuilder生成JobDetail;
步骤3:定义Trigger类,一般使用TriggerBuilder生成;
步骤4:定义Scheduler类,使用Scheduler .scheduleJob(job, trigger)将job和trigger进行关联;
步骤5:Scheduler.start();
步骤6:当需要关闭Scheduler时,使用Scheduler.shutdown();
下面将具体进行讲解。

二、Job、JobDetail、JobBuilder

官方定义:
  1. Job - an interface to be implemented by components that you wish to have executed by the scheduler.
  2. JobDetail - used to define instances of Jobs.
  3. JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.

Job

Job是一个接口类,下面是它的源码:

如果要实现自己的作业(任务),最简单的方式就是实现该接口,并实现接口中的execute()方法,当触发该作业时,就是执行execute()方法;
public class HelloJob implements Job {

    public HelloJob() {
} public void execute(JobExecutionContext context)
throws JobExecutionException
{
System.err.println("Hello! HelloJob is executing.");
}
}

JobDetail

JobDetail :用于定义Job的实例,一般该类都是通过JobBuilder生成;
JobBuilder:用于定义或创建JobDetail实例,使用了建造者模式;
JobDetail job = newJob(HelloJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.build();
//带参数
JobDetail job = JobBuilder.newJob(clazz)
                    .withIdentity(new JobKey(jobName, groupName))
                    .usingJobData(new JobDataMap(params))
                    .build();
从上面的接口类中我们可以知道,只要有了JobDetail的实现类,我们就可以获取到:
  1. key;
  2. JobClass;
  3. JobDataMap;等
那我们在自定义的Job中怎么才能获取到JobDetail相关信息呢?

由上面可知,当自定义的作业被触发时,我们可以通过JobExecutionContext获取到JobDetail,进而获取JobDataMap、JobKey、JobClass等等信息;


JobBuilder

这里JobBuilder使用了建造者模式,下面对其源码进行解析;
对于建造者模式,这里不进行详述,首先看下它的字段:


JobKey:作业的唯一标识,由name和group组成,如下:


jobClass:指定上述我们讲的自定义的Job(如:HelloJob );




JobDataMap:可以通过这个属性给自定义的Job(如:HelloJob)传递参数;

因为使用了建造者模式,所以实际创建的对象为:JobDetailImpl

JobDetailImpl类实现了JobDeteil接口,如下:
下图是类的层级结构图:



三、Trigger、TriggerBuilder

官方定义:
Trigger - a component that defines the schedule upon which a given Job will be executed.
TriggerBuilder - used to define/build Trigger instances.

下面是触发器层次结构,常用的有SimpleTrigger、CronTrigger等;


SimpleTrigger



主要属性:


CronTrigger

使用CronTrigger可以进行很强大的控制,关于Cron表达式,下面的章节会介绍;

主要的参数:



TriggerBuilder

首先看下实现的例子:使用的也是建造者模式(建造者模式可自行搜索);

TriggerBuilder的属性如下:


通过withIdentity()方法设定trigger唯一标识:


通过forJob()方法将Trigger和指定的Job绑定
前面我们已经知道:
  • 在使用JobBuilder创建JobDetail时,通过方法withIdentity()指定了JobDetail的JobKey
  • 这里通过TriggerBuilder的forJob()同样指定了JobKey;
==>只要上面两个JobKey设置的相同,则JobDetail和Trigger便绑定在一起了;
后面只需要使用Scheduler.scheduleJob(job,trigger)进行调度即可;


通过方法withSchedule设置调度器:

从上面可以看出,这个方法传递进去的实际上是一个调度器Scheduler的Builder,真正的调度器Scheduler还是需要通过ScheduleBuilder去创建,这里使用的还是建造者模式,从下面的层次可以看出,已经实现了4种ScheduleBuilder,这里以SimplesCheduleBuilder进行分析,其他类似

下面我们看看SimplesCheduleBuilder的源码实现;



上面是build方法,可以看出,真正创建的是:SimpleTriggerImpl类,这个类在上面已经介绍过,它是Trigger的一个实现类;



我们接着看TriggerBuilder的build方法:



四、Scheduler

官方定义:
Scheduler - the main API for interacting with the scheduler.
与调度程序交互的主要API。

具体实现类:

主要的方法:
  1. Scheduler  scheduler = StdSchedulerFactory.getDefaultScheduler();
  2. scheduler.schedeleJob(Job,trigger)
  3. scheduler.start();
  4. scheduler.shutdown();
说明:
只有在scheduler.start();之后,trigger以及Job才能有效运行;
shutdown用于关闭;

schedeleJob方法介绍
// Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);
官方介绍如下:

现在以StdScheduler作为示例进行介绍:

start()方法介绍

使用start()方法来激活Trigger,执行定时任务;




五、JobListener、SchedulerListener、TriggerListener




对监听进行注册:

      

六、Cron表达式

语法格式:

示例:


  • * ("all values") - used to select all values within a field. For example, "" in the minute field means *"every minute".

  • ? ("no specific value") - useful when you need to specify something in one of the two fields in which the character is allowed, but not the other. For example, if I want my trigger to fire on a particular day of the month (say, the 10th), but don't care what day of the week that happens to be, I would put "10" in the day-of-month field, and "?" in the day-of-week field. See the examples below for clarification.

  • - - used to specify ranges. For example, "10-12" in the hour field means "the hours 10, 11 and 12".

  • , - used to specify additional values. For example, "MON,WED,FRI" in the day-of-week field means "the days Monday, Wednesday, and Friday".

  • / - used to specify increments. For example, "0/15" in the seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and 50". You can also specify '/' after the '' character - in this case '' is equivalent to having '0' before the '/'. '1/3' in the day-of-month field means "fire every 3 days starting on the first day of the month".

  • L ("last") - has different meaning in each of the two fields in which it is allowed. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" means "the last friday of the month". You can also specify an offset from the last day of the month, such as "L-3" which would mean the third-to-last day of the calendar month. When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing/unexpected results.

  • W ("weekday") - used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month". So if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you specify "1W" as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' over the boundary of a month's days. The 'W' character can only be specified when the day-of-month is a single day, not a range or list of days.

The 'L' and 'W' characters can also be combined in the day-of-month field to yield 'LW', which translates to *"last weekday of the month"*.

  • # - used to specify "the nth" XXX day of the month. For example, the value of "6#3" in the day-of-week field means"the third Friday of the month" (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that month.
                                                                                                                                                                                                                          回到顶部

七、程序示例


AbstractSchedule类:抽象基类



  1. package com.sssppp.TimerSchedule.quartz.schedule;
  2. import java.util.Date;
  3. import java.util.Map;
  4. import java.util.Properties;
  5. import org.quartz.CronScheduleBuilder;
  6. import org.quartz.CronTrigger;
  7. import org.quartz.JobBuilder;
  8. import org.quartz.JobDataMap;
  9. import org.quartz.JobDetail;
  10. import org.quartz.JobKey;
  11. import org.quartz.Scheduler;
  12. import org.quartz.SchedulerException;
  13. import org.quartz.TriggerBuilder;
  14. import org.quartz.impl.StdSchedulerFactory;
  15. import com.sssppp.TimerSchedule.quartz.listeners.MyJobListener;
  16. import com.sssppp.TimerSchedule.quartz.listeners.MySchedulerListener;
  17. import com.sssppp.TimerSchedule.quartz.listeners.MyTriggerListener;
  18. public abstract class AbstractSchedule {
  19. public Scheduler scheduler = null;
  20. private static final String JOB_GROUPNAME = "MY_JOB_GROUP";
  21. private static final String TRIGGER_GROUPNAME = "MY_TRIGGER_GROUP";
  22. /**
  23. * 初始化Scheduler,并添加Listeners
  24. */
  25. public AbstractSchedule() {
  26. try {
  27. if (scheduler == null) {
  28. System.out.println("Begin init scheduler...");
  29. try {
  30. Properties props = new Properties();
  31. props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,
  32. "org.quartz.simpl.SimpleThreadPool");
  33. props.put("org.quartz.threadPool.threadCount", "100");// 同时100个线程运行
  34. props.put("org.quartz.jobStore.misfireThreshold", "180000");// trigger过期30分钟内还有效
  35. StdSchedulerFactory factory = new StdSchedulerFactory();
  36. factory.initialize(props);
  37. scheduler = factory.getScheduler();
  38. } catch (SchedulerException e) {
  39. e.printStackTrace();
  40. }
  41. scheduler.getListenerManager().addJobListener(new MyJobListener());
  42. scheduler.getListenerManager().addSchedulerListener(
  43. new MySchedulerListener());
  44. scheduler.getListenerManager().addTriggerListener(
  45. new MyTriggerListener());
  46. }
  47. } catch (Exception e) {
  48. System.err.println("Init scheduler failed, error message :" + e);
  49. }
  50. }
  51. public abstract Scheduler handleJob(String jobName, String triggerName,
  52. String cronStr);
  53. @SuppressWarnings({ "unchecked", "rawtypes" })
  54. public void scheduleJob(String jobName, String triggerName, String express,
  55. Class clazz) {
  56. JobDetail job = null;
  57. CronTrigger trigger = null;
  58. try {
  59. job = JobBuilder.newJob(clazz).withIdentity(jobName, JOB_GROUPNAME)
  60. .build();
  61. trigger = TriggerBuilder.newTrigger()
  62. .withIdentity(triggerName, TRIGGER_GROUPNAME)
  63. .forJob(jobName, JOB_GROUPNAME)
  64. .withSchedule(CronScheduleBuilder.cronSchedule(express))
  65. .build();
  66. } catch (Exception e) {
  67. System.err.println("scheduler ParseException!" + e);
  68. }
  69. Date date = null;
  70. try {
  71. date = scheduler.scheduleJob(job, trigger);
  72. } catch (SchedulerException e) {
  73. System.err.println("scheduler SchedulerException!" + e);
  74. }
  75. System.out.println(job.getKey().toString()
  76. + " has been scheduled to run at: " + date
  77. + " and repeat based on expression: "
  78. + trigger.getCronExpression());
  79. }
  80. /**
  81. * 创建Job和Trigger,并使用scheduler将job和Trigger进行关联
  82. *
  83. * @param jobName
  84. * @param triggerName
  85. * @param express
  86. * :cronStr表达式
  87. * @param clazz
  88. * :job的class
  89. * @param params
  90. * :Job使用的参数
  91. */
  92. @SuppressWarnings({ "unchecked", "rawtypes" })
  93. public void scheduleJobWithParams(String jobName, String triggerName,
  94. String express, Class clazz, Map<String, Object> params) {
  95. JobDetail job = null;
  96. CronTrigger trigger = null;
  97. try {
  98. job = JobBuilder.newJob(clazz)
  99. .withIdentity(new JobKey(jobName, JOB_GROUPNAME))
  100. .usingJobData(new JobDataMap(params)).build();
  101. trigger = TriggerBuilder.newTrigger()
  102. .withIdentity(triggerName, TRIGGER_GROUPNAME)
  103. .forJob(jobName, JOB_GROUPNAME)
  104. .withSchedule(CronScheduleBuilder.cronSchedule(express))
  105. .build();
  106. } catch (Exception e) {
  107. System.err.println("scheduler ParseException!" + e);
  108. }
  109. Date date = null;
  110. try {
  111. date = scheduler.scheduleJob(job, trigger);
  112. } catch (SchedulerException e) {
  113. System.err.println("scheduler SchedulerException!" + e);
  114. }
  115. System.out.println(job.getKey().toString()
  116. + " has been scheduled to run at: " + date
  117. + " and repeat based on expression: "
  118. + trigger.getCronExpression());
  119. }
  120. /**
  121. * Starts the Scheduler's threads that fire Triggers
  122. */
  123. public void startJob() {
  124. try {
  125. this.scheduler.start();
  126. } catch (SchedulerException e) {
  127. System.err.println("trigger job error!" + e);
  128. }
  129. }
  130. public boolean stopJob(String jobName) {
  131. boolean b = false;
  132. JobKey jobkey = new JobKey(jobName, JOB_GROUPNAME);
  133. try {
  134. if (this.scheduler.checkExists(jobkey)) {
  135. b = this.scheduler.deleteJob(jobkey);
  136. System.out.println("Stop Job[" + jobName + "] success.");
  137. }
  138. } catch (SchedulerException e) {
  139. System.err.println("Stop job fail.");
  140. e.printStackTrace();
  141. }
  142. return b;
  143. }
  144. public void shutdownScheduler() {
  145. try {
  146. this.scheduler.shutdown(true);
  147. System.out.println("Shutdown scheduler success.");
  148. } catch (SchedulerException e) {
  149. System.err.println("Shutdown Scheduler fail.");
  150. e.printStackTrace();
  151. }
  152. }
  153. }

MyJobSchedule.java
  1. package com.sssppp.TimerSchedule.quartz.schedule;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import org.quartz.Scheduler;
  5. import com.sssppp.TimerSchedule.quartz.Jobs.MyJob;
  6. public class MyJobSchedule extends AbstractSchedule {
  7. private static MyJobSchedule myJobSchedule = new MyJobSchedule();
  8. private MyJobSchedule() {
  9. }
  10. public static MyJobSchedule getInstance() {
  11. return myJobSchedule;
  12. }
  13. @Override
  14. public Scheduler handleJob(String jobName, String triggerName,
  15. String cronStr) {
  16. Map<String, Object> params = new HashMap<String, Object>();
  17. params.put(MyJob.JOB_PARAM_KEY, "This is myJob param");
  18. scheduleJobWithParams(jobName, triggerName, cronStr, MyJob.class, params);
  19. startJob();
  20. return this.scheduler;
  21. }
  22. }

MyJob.java

  1. package com.sssppp.TimerSchedule.quartz.Jobs;
  2. import java.util.Date;
  3. import org.quartz.Job;
  4. import org.quartz.JobExecutionContext;
  5. import org.quartz.JobExecutionException;
  6. import com.ibm.icu.text.SimpleDateFormat;
  7. public class MyJob implements Job {
  8. public final static String JOB_PARAM_KEY = "jobParam";
  9. @Override
  10. public void execute(JobExecutionContext jobexecutioncontext)
  11. throws JobExecutionException {
  12. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  13. // 获取传递给Job的参数
  14. String param = (String) jobexecutioncontext.getJobDetail()
  15. .getJobDataMap().get(JOB_PARAM_KEY);
  16. System.out.println("Now exec MyJob,param【" + param + "】, time:"
  17. + sdf.format(new Date()));
  18. }
  19. }

QuartzManager.java
  1. package com.sssppp.TimerSchedule.quartz;
  2. import com.sssppp.TimerSchedule.quartz.schedule.MyJobSchedule;
  3. public class QuartzManager {
  4. private static final QuartzManager quartzManager = new QuartzManager();
  5. private static final String MY_JOB_NAME = "MY_JOB_NAME";
  6. private static final String MY_TRIGGER_NAME = "MY_TRIGGER_NAME";
  7. private static final String MY_JOB_CRONSTR = "0/5 * * * * ?";
  8. private QuartzManager() {
  9. }
  10. public static QuartzManager getInstance() {
  11. return quartzManager;
  12. }
  13. public void startMyJob() {
  14. MyJobSchedule.getInstance().handleJob(MY_JOB_NAME, MY_TRIGGER_NAME,
  15. MY_JOB_CRONSTR);
  16. }
  17. public void stopMyJobAndShutdownScheduler() {
  18. MyJobSchedule.getInstance().stopJob(MY_JOB_NAME);
  19. MyJobSchedule.getInstance().shutdownScheduler();
  20. }
  21. }





TestCase.java

  1. package com.sssppp.TimerSchedule.quartz;
  2. public class TestCase {
  3. @SuppressWarnings("static-access")
  4. public static void main(String[] args) throws InterruptedException {
  5. QuartzManager.getInstance().startMyJob();
  6. Thread.currentThread().sleep(12 * 1000);
  7. QuartzManager.getInstance().stopMyJobAndShutdownScheduler();
  8. }
  9. }























【原创】Quartz代码详解的更多相关文章

  1. 任务调度Cron表达式及Quartz代码详解

    在线Cron表达式生成器 http://cron.qqe2.com/ cron表达式详解 http://www.cnblogs.com/linjiqin/archive/2013/07/08/3178 ...

  2. 【原创】Junit4详解二:Junit4 Runner以及test case执行顺序和源代码理解

    概要: 前一篇文章我们总体介绍了Junit4的用法以及一些简单的测试.之前我有个疑惑,Junit4怎么把一个test case跑起来的,在test case之前和之后我们能做些什么? Junit4执行 ...

  3. quartz配置文件详解

    quartz配置文件详解(转载)     quartz学习总结: 一.关于job:    用Quartz的行话讲,作业是一个执行任务的简单Java类.任务可以是任何Java代码.只需你实现org.qu ...

  4. Quartz 入门详解

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来创建简单或为运行十个,百个, ...

  5. ASP.NET MVC 5 学习教程:生成的代码详解

    原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...

  6. Quartz学习——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成详解(四)

    当任何时候觉你得难受了,其实你的大脑是在进化,当任何时候你觉得轻松,其实都在使用以前的坏习惯. 通过前面的学习,你可能大致了解了Quartz,本篇博文为你打开学习SSMM+Quartz的旅程!欢迎上车 ...

  7. Quartz学习——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成详解(转)

    通过前面的学习,你可能大致了解了Quartz,本篇博文为你打开学习SSMM+Quartz的旅程!欢迎上车,开始美好的旅程! 本篇是在SSM框架基础上进行的. 参考文章: 1.Quartz学习——Qua ...

  8. (转) Quartz学习——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成详解(四)

    http://blog.csdn.net/u010648555/article/details/60767633 当任何时候觉你得难受了,其实你的大脑是在进化,当任何时候你觉得轻松,其实都在使用以前的 ...

  9. Quartz 入门详解 专题

    Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that a ...

随机推荐

  1. ANTLR3完全参考指南读书笔记[08]

    前言 不要让用户被那些“专业术语”吓住! 用心设计的提示和反馈信息是软件设计者的“职业良心”.   内容 1 存在哪些错误? 2 美化错误提示 3 错误恢复策略   1 存在哪些错误? 在DSL语言开 ...

  2. ajax 上传

    使用FormData,进行Ajax请求并上传文件:具体代码如下: html代码: <!DOCTYPE html><html lang="en"><he ...

  3. C陷阱与缺陷 1

    1,符号之间的空白被忽略 符号中间不能嵌入空白 2,词法分析中的贪心法 a---b 和 a-- -b相同 和 a- --b不同 1 a=b/*p //根据贪心法 /*被解释成 注释符,便不再往下读,直 ...

  4. php归获取当前目录下的二级目录数 和文件数

    <?php        header('Content-Type: text/html; charset=gb2312');        // $baseDir = "/www/u ...

  5. Reverse a Singly LinkedList

    Reverse a Singly LinkedList * Definition for singly-linked list. * public class ListNode { * int val ...

  6. centos 6.4/redhat 6.4 安装gitlab

    一,把所有包升级到最新版本 yum -y upgrade 二,安装最新版ruby 2.1.5 步骤http://my.oschina.net/duolus/blog/348353 三,安装官方给出的o ...

  7. Questions that are independent of programming language. These questions are typically more abstract than other categories.

    Questions that are independent of programming language.  These questions are typically more abstract ...

  8. linux操作文本文件

    打开文件 #vi 文件名 保存退出 从编辑模式退到命令行模式,按esc键 保存退出命令 #:wq 强制退出,不保存 #:q!

  9. python tornado框架实现CRUD

    1.本例采用postgresql数据库,创建数据表 user_tbl ),signup_date date); 2.webapi接口 (1)tornado框架配置 t_tornado.py #-*- ...

  10. TFS 强制撤销别人签出的代码

    有个同事离职一段时间了,今天改一下她的代码,发现有个文件签出了,晕,而且TFS用的也是只允许单用户签出. 1,找原来的用的机器,已经被人占用了,系统已经重做. 2,只有用命令行来搞了. 大致如下: t ...