http://blog.csdn.net/qwe6112071/article/details/50991563

Quartz框架需求引入

在现实开发中,我们常常会遇到需要系统在特定时刻完成特定任务的需求,在《spring学习笔记(14)引介增强详解:定时器实例:无侵入式动态增强类功能》,我们通过引介增强来简单地模拟实现了一个定时器。它可能只需要我们自己维护一条线程就足以实现定时监控。但在实际开发中,我们遇到的需求会复杂很多,可能涉及多点任务调度,需要我们多线程并发协作、线程池的维护、对运行时间规则进行更细粒度的规划、运行线程现场的保持与恢复等等。如果我们选择自己来造轮子,可能会遇到许多难题。这时候,引入Quartz任务调度框架会是一个很好的选择,它: 
1. 允许我们灵活而细粒度地设置任务触发时间,比如常见的每隔多长时间,或每天特定时刻、特定日子(如节假日),都能灵活地配置这些成相应时间点来触发我们的任务 
2. 提供了调度环境的持久化机制,可以将任务内容保存到数据库中,在完成后删除记录,这样就能避免因系统故障而任务尚未执行且不再执行的问题。 
3. 提供了组件式的侦听器、各种插件、线程池等。通过侦听器,我们可以引入我们的事件机制,配合上异步调用,既能为我们的业务处理类解耦,同时还可能提升用户体验,关于事件机制的基本概念、解耦特性及其异步调用可移步参考我的另一篇文章《spring学习笔记(15)趣谈spring 事件:实现业务逻辑解耦,异步调用提升用户体验 》

实例解析概念

在quartz中,有几个核心类和接口:Job、JobDetail、Trigger、Calendar、Scheduler。 
下面我们结合实例来分析这些类的角色定位。 
现在我们有一个新闻网站,它有一张任务日志表,记录着我们的不同任务,比如每隔三十分钟要根据文章的阅读量和评论量来生成我们的最热文章列表。在每天早晚12点,定时从其他新闻网站扒取一定量新闻,在每周一晚上12点到3点进行论坛封闭维护,而如果遇到节假日则不维护等。在以上实例中:

  1. 生成最热文章扒取新闻论坛封闭维护都是我们的Job,它定义了我们的需要执行的任务,是一个抽象的接口.
  2. 如果我们要具体到每隔三十分钟生成最热文章早晚12点扒取新闻等,在我们的具体任务执行时刻,我们就需要能够描述Job及其他相关静态信息jobDetail,它相当于是我们的Job+具体实现细节
  3. Trigger则描述了Job执行的时间触发规则,比如每隔三十分钟早晚12点
  4. 而这里的Calendar可以看成是一些日历特定时间点的集合,比如我们这里遇到节假日则不维护,节假日如国庆节、愚人节等等,都是我们的日历特定时间点。
  5. Scheduler就是我们的任务日志表,它是一个容器,记载(容纳)了我们前面的工作、触发时间等内容。

具体用法详解

通过实例,我们对quartz的核心类有了较清晰的功能定位,根据Quratz的不同版本,这几个核心类有较大改动,具体的操作不太相同,但是思路是相同的;比如1.+版本jar包中,JobDetail是个类,直接通过构造方法与Job类关联。SimpleTrigger和CornTrigger是类;在2.+jar包中,JobDetail是个接口,SimpleTrigger和CornTrigger是接口。下面详细地分析它们的具体用法:

1. Job

Job是一个接口,只有一个void execute(JobExecutionContext jec)方法,JobExecutionContext提供了我们的任务调度上下文信息,比如,我们可以通过JobExecutionContext获取job相对应的JobDetail、Trigger等信息,我们在配置自己的内容时,需要实现此类,并在execute中重写我们的任务内容。下面是我们的扒取新闻工作实例:

public class pickNewsJob implements Job { @Override public void execute(JobExecutionContext jec) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); System.out.println("在"+sdf.format(new Date())+"扒取新闻"); } } 

2. JobDetail

Quartz在每次执行任务时,都会创建一个Job实例,并为其配置上下文信息,jobDetail有一个成员属性JobDataMap,存放了我们Job运行时的具体信息,在后面我们会详细提到。 
1. 在1.+版本中,它作为一个类,常用的构造方法有:JobDetail(String name, String group, Class jobClass),我们需要指定job的名称,组别和实现了Job接口的自定义任务类。实例如JobDetail jobDetail =new JobDetail("job1", "jgroup1", pickNewsJob.class); 
2. 而在2.+版本中,我们则通过一下方法创建JobBuilder.newJob(自定义任务类).withIdentity(任务名称,组名).build();实例如JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class).withIdentity(“job1”,”group1”).build();`

3. Scheduler

先讲Scheduler,方便后讲解Trigger时测试。 
Scheduler作为我们的“任务记录表”,里面(可以)配置大量的Trigger和JobDetail,两者在 Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。下面是使用Schduler的实例:

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//将jobDetail和Trigger注册到一个scheduler里,建立起两者的关联关系
scheduler.scheduleJob(jobDetail,Trigger);scheduler.start();//开始任务调度

在一个scheduler被创建后,它处于”STAND-BY”模式,在触发任何job前需要使用它的start()方法来启动。同样的,如果我们想根据我们的业务逻辑来停止定时方案执行,可以使用scheduler.standby()方法

3. Trigger

Trigger描述了Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类。

1. SimpleTrigger

如果嵌入事件机制只触发一次,或意图使Job以固定时间间隔触发,则使用SimpleTrigger较合适,它有多个构造函数,其中一个最复杂的构造函数为: 
SimpleTrigger(String name, String group, String jobName, String jobGroup, Date startTime, Date 
endTime, int repeatCount, long repeatInterval)
参数依次为触发器名称、触发器所在组名、工作名、工作所在组名、开始日期、结束日期、重复次数、重复间隔。 
1. 如果我们不需同时设置这么多属性,可调用其他只有部分参数的构造方法,其他参数也可以通过set方法动态设置。 
2. 这里需要注意的是,如果到了我们设置的endTime,即时重复次数repeatCount还没有达到我们预设置的次数。任务也不会再此执行。 
下面是1.+版本的创建实例

//创建一个触发器,使任务从现在开始、每隔两秒执行一次,共执行10次
SimpleTrigger simpleTrigger = new SimpleTrigger("triiger1");//至少需要设置名字以标识当前触发器,否则在调用时会报错
simpleTrigger.setStartTime(new Date()); simpleTrigger.setRepeatInterval(2000); simpleTrigger.setRepeatCount(10);

下面是2.+版本的创建实例

SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1")//配置触发器名称.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))//配置重复次数和间隔时间 .startNow()//设置从当前开始 .build();//创建操作

通过TriggerBuilder,我们可以通过方法方便地配置触发器的各种参数。

2. CronTrigger

通过Cron表达式定义复杂的时间调度方案,具体内容我们在下一篇详细提到

4. Calendar

在实际的开发中,我们可能需要根据节假日来调整我们的任务调度方案。实例如下:

//第一步:创建节假日类// ②四一愚人节
Calendar foolDay = new GregorianCalendar();    //这里的Calendar是 java.util.Calendar。根据当前时间所在的默认时区创建一个“日子”
foolDay.add(Calendar.MONTH, 4); foolDay.add(Calendar.DATE, 1); // ③国庆节 Calendar nationalDay = new GregorianCalendar(); nationalDay.add(Calendar.MONTH, 10); nationalDay.add(Calendar.DATE, 1); //第二步:创建AnnualCalendar,它的作用是排除排除每一年中指定的一天或多天 AnnualCalendar holidays = new AnnualCalendar(); //设置排除日期有两种方法 // 第一种:排除的日期,如果设置为false则为包含(included) holidays.setDayExcluded(foolDay, true); holidays.setDayExcluded(nationalDay, true); //第二种,创建一个数组。 ArrayList<Calendar> calendars = new ArrayList<Calendar>(); calendars.add(foolDay); calendars.add(nationalDay); holidays.setDaysExcluded(calendars); //第三步:将holidays添加进我们的触发器 simpleTrigger.setCalendarName("holidays"); //第四步:设置好然后需要在我们的scheduler中注册 scheduler.addCalendar("holidays",holidays, false,false);,注意这里的第一个参数为calendarName,需要和触发器中添加的Calendar名字像对应。

在这里,除了可以使用AnnualCalendar外,还有CronCalendar(表达式),DailyCalendar(指定的时间范围内的每一天),HolidayCalendar(排除节假日),MonthlyCalendar(排除月份中的数天),WeeklyCalendar(排除星期中的一天或多天)

至此,我们的核心类基本讲解完毕,下面附上我们的完整测试代码:

/*********************1.+版本*********************/
public class pickNewsJob implements Job { @Override public void execute(JobExecutionContext jec) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); System.out.println("在" + sdf.format(new Date()) + "扒取新闻"); } public static void main(String args[]) throws SchedulerException { JobDetail jobDetail =new JobDetail("job1", "jgroup1", pickNewsJob.class); SimpleTrigger simpleTrigger = new SimpleTrigger("triiger1"); simpleTrigger.setStartTime(new Date()); simpleTrigger.setRepeatInterval(2000); simpleTrigger.setRepeatCount(10); simpleTrigger.setCalendarName("holidays"); //设置需排除的特殊假日 AnnualCalendar holidays = new AnnualCalendar(); // 四一愚人节 Calendar foolDay = new GregorianCalendar(); // 这里的Calendar是 ava.util.Calendar。根据当前时间所在的默认时区创建一个“日子” foolDay.add(Calendar.MONTH, 4); foolDay.add(Calendar.DATE, 1); // 国庆节 Calendar nationalDay = new GregorianCalendar(); nationalDay.add(Calendar.MONTH, 10); nationalDay.add(Calendar.DATE, 1); //排除的日期,如果设置为false则为包含(included) holidays.setDayExcluded(foolDay, true); holidays.setDayExcluded(nationalDay, true); /*方法2:通过数组设置 ArrayList<Calendar> calendars = new ArrayList<Calendar>(); calendars.add(foolDay); calendars.add(nationalDay); holidays.setDaysExcluded(calendars);*/ //创建scheduler SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.addCalendar("holidays", holidays, false, false); scheduler.scheduleJob(jobDetail, simpleTrigger); scheduler.start(); } } /*******************2.+版本***************/ public class pickNewsJob implements Job { @Override public void execute(JobExecutionContext jec) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); System.out.println("在"+sdf.format(new Date())+"扒取新闻"); } public static void main(String args[]) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class) .withIdentity("job1", "group1").build(); SimpleTrigger simpleTrigger = TriggerBuilder .newTrigger() .withIdentity("trigger1") .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2)) .startNow() .build(); //设置需排除的特殊假日 AnnualCalendar holidays = new AnnualCalendar(); // 四一愚人节 Calendar foolDay = new GregorianCalendar(); // 这里的Calendar是 ava.util.Calendar。根据当前时间所在的默认时区创建一个“日子” foolDay.add(Calendar.MONTH, 4); foolDay.add(Calendar.DATE, 1); // 国庆节 Calendar nationalDay = new GregorianCalendar(); nationalDay.add(Calendar.MONTH, 10); nationalDay.add(Calendar.DATE, 1); //排除的日期,如果设置为false则为包含(included) holidays.setDayExcluded(foolDay, true); holidays.setDayExcluded(nationalDay, true); /*方法2:通过数组设置 ArrayList<Calendar> calendars = new ArrayList<Calendar>(); calendars.add(foolDay); calendars.add(nationalDay); holidays.setDaysExcluded(calendars);*/ //创建scheduler SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.addCalendar("holidays", holidays, false, false); scheduler.scheduleJob(jobDetail, simpleTrigger); scheduler.start(); } }

可见,两个不同版本的主要区别在于JobDetail和Triiger的配置。

此外,除了使用scheduler.scheduleJob(jobDetail, simpleTrigger)来建立jobDetail和simpleTrigger的关联外,在1.+版本中的配置还可以采用如下所示方式

simpleTrigger.setJobName("job1");//jobName和我们前面jobDetail的的名字一致
simpleTrigger.setJobGroup("jgroup1");//jobGroup和我们之前jobDetail的组名一致
scheduler.addJob(jobDetail, true);//注册jobDetail,此时jobDetail必须已指定job名和组名,否则会抛异常Trigger's related Job's name cannot be null scheduler.scheduleJob(simpleTrigger);//注册triiger必须在注册jobDetail之后,否则会抛异常Trigger's related Job's name cannot be null

这里还需要注意的是,如果我们使用scheduler.addCalendar("holidays", holidays, false, false)必须在向scheduler注册trigger之前scheduler.scheduleJob(simpleTrigger),否则会抛异常:Calendar not found: holidays

而在2.+版本中,我尝试在创建triiger时用forJob(“job1”, “jgroup1”)来绑定job名和组名

SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1").forJob("job1", "jgroup1")//在这里绑定.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2)) .startNow() .build();

//后面是一样的 
scheduler.addJob(jobDetail, true); 
scheduler.scheduleJob(simpleTrigger);

在运行时,却会抛出异常: Jobs added with no trigger must be durable. 
显然是绑定失败了,目前暂未找到解决方法,如果有找到解决方法的朋友,恳请告诉我一下,十分感谢!

转载于:https://www.cnblogs.com/telwanggs/p/7237762.html

(转)Quartz任务调度(1)概念例析快速入门相关推荐

  1. [JavaWeb-HTML]HTML概念介绍和快速入门

    HTML 1. 概念:是最基础的网页开发语言* Hyper Text Markup Language 超文本标记语言* 超文本:* 超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本 ...

  2. Java任务调度之Quartz快速入门

    首先所谓的任务调度指的是软件系统在从某个时间节点开始,以固定的频率,除去特定的某些时间段,定期执行某项任务,比如可以在某个夜深人静的时候做一些大批量的文件传输.备份等耗费极大资源的工作,那么通过这个概 ...

  3. Quartz-任务调度概述及Quartz(2.2.X)快速入门

    文章目录 概述 Quartz 概述 Quartz 基础结构 Job JobDetail Trigger Calendar Scheduler ThreadPool 注意 快速入门 Quartz(2.2 ...

  4. 从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  5. quartz java spring_从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  6. 干货|BAT物联云IoT协议例析

    点击上方"中兴开发者社区",关注我们 每天读一篇一线开发者原创好文 近年来,物联网(IoT,Internet of Things)已经从概念阶段走向大规模应用.据Gartner统计 ...

  7. java任务调度定时器,从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  8. Quartz任务调度框架

    Quartz 基本概念及原理 作为一个优秀的开源调度框架,Quartz 具有以下特点: 1.强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求: 2. 灵活的应用方式,例如支持任务 ...

  9. Quartz 框架快速入门(二)

    尽可能的用声明式处理软件配置,其次才考虑编程式的方式.在上一篇<Quartz 框架快速入门(一)>中,如果我们要在 Job 启动之后改变它的执行时间和频度,必须去修改源代码重新编译.这种方 ...

最新文章

  1. Java关键字和保留字
  2. mysql 加密 en_以极少的停机时间加密运行 MySQL 或 MariaDB 的 Amazon RDS 数据库实例...
  3. C++基础::shared_ptr 编程细节(三)
  4. bzoj4987: Tree(树形dp)
  5. [转]详细解说:简单CSS3实现炫酷读者墙
  6. 全网最全Linux常用命令
  7. Sublime Text3 插件集合
  8. 《复杂网络》的课程笔记,复杂网络,小世界网络,随机网络,无标度网络,入门
  9. 「excel小技巧」一秒快速求和多行数值
  10. (Hankson的逆问题)
  11. 二、分布式系统设计策略
  12. 教资报名网站显示无法访问此页面
  13. AutoHotKey简单入门
  14. 心紊妥布俅善市陀炎妇涣上街彻躺
  15. cent os 主题安装
  16. 解析协同办公“协同”为何意,数字化办公又如何轻松“破题”?
  17. 深度学习框架PyTorch入门与实践:第八章 AI艺术家:神经网络风格迁移
  18. 第十三章 系统错误消息 - 一般系统错误消息 S - Z
  19. 全球十大资质正规现货黄金交易平台排名榜单(最新版汇总)
  20. idea中重新加载新的依赖方法

热门文章

  1. 消费者Heartbeat分析
  2. (130)FPGA面试题-FPGA设计中波特率和比特率的区别
  3. DDR3初始化时间测试
  4. java中用new创建一个对象的过程解析_【漫画】Java对象的创建和访问全过程详解...
  5. QT编译boost库
  6. MFC1、动态创建CButton
  7. mysql全拼_Mysql中取得汉字的全拼、拼音首字母
  8. 集群的可扩展性及其分布式体系结构(2)-下
  9. (9)引入哈希桶的概念来实现一个哈希表
  10. [设计模式] - 工厂模式