【总结】Quartz整理

2019-04-15 17:54发布

[img]http://dl.iteye.com/upload/picture/pic/136093/2a0e8f99-0f57-3510-8806-b76a02a76c73.jpg[/img]

官网:[url]http://www.quartz-scheduler.org[/url]
Java文档(重要):[url]http://www.quartz-scheduler.org/api/previous_versions/2.0.2/index.html[/url]
GitHub:[url]https://github.com/quartz-scheduler/quartz[/url]

Quartz Job是项目开发中经常用到的第三方开源Jar,由James House创建并于2001年初加入到SourceForge下)。

因为Job大家都比较熟悉,就不具体讲例子,就讲下实际应用中碰到的问题吧。

[b]1.基本接口类(核心)介绍[/b]
Scheduler
Job
JobDetail
Trigger
JobBuilder
TriggerBuilder

其中Scheduler, Job, Trigger都可以配置在xml文件中。


[b]2.怎样理解Sheduler拥有的线程池[/b]
Scheduler本身就是一个容器,它维护着Quartz的各种组件并实施调度的规则。Scheduler还拥有一个线程池,线程池为任务提供执行线程――这比执行任务时简单地创建一个新线程要拥有更高的效率,同时通过共享节约资源的占用。通过线程池组件的支持,对于繁忙度高、压力大的任务调度,Quartz将可以提供良好的伸缩性。

我们可以在scheduler初始化时设定tread的数量,比如5个线程。那么如果我们配置一个Job,并让这个Job每秒执行1次,然而这个Job实现类里如果要执行10秒(等待),那么执行的结果顺序会是怎样呢?会变成每10秒执行一次吗?

在第1个Job启动后,第2个Job隔1秒还是会执行,直到第5个Job被执行,然后才是等待。原因是Scheduler会用线程池去管理Job,这个跟其设定的Thread数量有关。


[b]3.可持久化的Job[/b]
这个算是Quartz Job的特点之一。Quartz包含了一个叫JobStore的接口。其中JDBCJobStore和RAMJobStore都是其实现类,JDBCJobStore中的job和trigger都配置在数据库中(Quartz会在其配置的数据库中创建一系列的表),而RAMJobStore是将job等信息存放在内存中。

其利弊是,JDBCJobStore因为要和数据库进行交互,必然效率上是比不上RAMJobStore,但其优点是job等信息不会随着程序的重启而丢失(对于Misfire的情况可以配置策略,比如重启后再继续执行Job等)。

多说一句,对于JDBCJobStore之前有碰到的一个误区。我们的项目是有多个节点(负载均衡)的,那么有时候要执行一个Job,只需同一时间点上在其中的一台node上执行,而默认的scheduler执行是跟Thread有关,跟Node并没有关系。之前的误解是以为配置了JDBCJobStore就可以了,其实这样并不能阻止多个Node一起执行一个Job。

[u]JDBCJobStore的核心是将Job信息存放在数据库中,但这跟Job被实例化了多少次并没有多少关系。(被实例多少次是由Scheduler的线程池控制的)[/u]

在Quartz 1.8版本有个接口叫StatefulJob,这个接口在2.0版本被两个Annotation代替,即:@PersistJobDataAfterExecution和@DisallowConcurrentExecution。

[u]而我上述的需求就是要阻止Job在同一时间被多次实例化,即需要配置@DisallowConcurrentException。[/u]

另外,@PersistJobDataAfterExecution的作用是告诉Quartz在成功执行了一个Job后,更新JobDetail中的JobDataMap数据,使得该job(即JobDetail)在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。


[b]4.与Spring结合[/b]
一个Job在继承Quartz Job接口后,就可以在其execute方法里写业务逻辑了。但是默认情况下该Job取不到Spring的上下文(即Bean)。解决办法可以是手动通过ApplicationContext取到相应的Bean或是把Quartz配置到Spring的Context里。