10.配置,资源使用和调度器工厂
Quartz是以标准组件的方式组织的,所以,使它运行起来,一些组件需要被联合起来。
在Quartz能够工作之前,需要配置的主要组件有:
线程池
作业储存
数据源(需要的话)
调度器自己
在运行jobs时,线程池为Quartz提供了一系列的线程。在线程池里的线程越多,
能够并行执行的jobs就越多。但是,太多的线程会使系统瘫痪。大部分的Quartz
用户发现,5个线程就足够了-因为他们在指定时间里只有少于100的jobs,这些jobs并不都是在同一时刻执行,jobs完成得也很快的。其他的用户发现他们需要10、15、50或者100个线程-因为他们在不同的调度器里用了上万个触发器,在给定的时间里,平均在10到100个jobs试着执行。为调度器找到合适的线程数量完全依赖于你用调度起来做什么。不在乎线程数量,而要确保你有足够的线程来使jobs执行。如果一个触发器的触发时间到来了,可是没有一个能够用的线程,Quartz将会等到可用线程的来临,然后job将会在几毫秒后执行。这可能会引起不触发-如果不在属性文件里给调度器配置“misfire
线程池接口是在org.quartz.spi包里定义的,你能够创建一个线程池以自己的方法。Quartz装配了一个简单(但是很好的)的线程池,是org.quartz.simpl.SimpleThreadPool。这个线程池简单的维护一些在池里固定的线程-不会增加也不会减少。但是它能够做很多事而且经过测试了的,几乎每个Quartz用户用这个线程池。
最后,你需要创建你的Scheduler实例。Scheduler需要提供他的名称,说明RMI的设置,处理JobStore和ThreadPool的实例。RMI设置包括调度器是否作为一个RMI服务器而创建。StdSchedulerFactory也能够产生调度器的实例,这些实例实际上是创建在远程进程中的调度器代理(RMI桩)。
StdSchedulerFactory
StdSchedulerFactory实现了org.quartz.SchedulerFactory接口。它用了一系列的属性(java.util.Properties)来创建和初始化一个Quartz的调度器。这些属性通常保存和加载在一个文件里,但是也可以通过你的程序创建直接交给工厂处理。在工厂上调用getScheduler()就可以产生调度器,初始化它(还有线程池,JobStore和数据源),然后返回一个句柄到这个公共的接口。
//
SchedulerFactory
Scheduler
scheduler.start();
用指定的属性对象初始化:
SchedulerFactory
sf.initialize(schedulerProperties);//
Scheduler
scheduler.start();
用指定的属性文件初始化:
SchedulerFactory
sf.initialize(fileName);//属性文件全名
Scheduler
scheduler.start();
DirectSchedulerFactory
DirectSchedulerFactory是另外的一个SchedulerFactory实现。在更多的编程方法里创建调度器时,他很有用。他的用法不被赞成,原因有:1.它需要用户更清楚的知道他们在做什么。2.它不允许配置,就是说,你必须要在代码里配置所有的调度器属性。
Logging
Quartz给它所有需要的日志是使用org.apache.commons.logging框架的。Quartz没有产生很多的日志信息。仅有一些在初始化时关于一些jobs正在执行的问题的信息。为了调整日志设置,我们需要了解Jakarta
11.高级(企业)特性
集群
目前集群仅以JDBC-Jobstore
通过设置org.quartz.jobStore.isClustered属性为“true”来使用集群。在集群里的每个调度器实例应该用一样的quartz.properties文件。集群会有如下异常:线程池大小不同,属性org.quartz.scheduler.instanceName值不同。其实在集群的每个节点都有一个唯一的实例ID,要达到这样也很简单,也不需要不同的属性文件,只要将属性org.quartz.scheduler.instanceId的值设置为“AUTO”。
不要在一个分离开的机器上运行集群,除非他们的时钟是用时钟同步服务同步过的。如果不熟悉怎样同步,参考:http://www.boulder.nist.gov/timefreq/service/its.htm
其他调度器实例在用数据表时,不要触发一个也用到这些数据表的不是集群的调度器实例。你会得到一些没用的数据。
JTA
在第9节解释过JobStores,JobStoreCMT允许Quartz调度一些具有很大JTA事务的操作。
通过设置“org.quartz.scheduler.wrapJobExecutionInUserTr
除了在JTA事务里Quartz自动地和job的执行挂钩之外,当使用JobStoreCMT时也可以调用你在调度器接口里的实现的方法,确保你在调用一个调度器上的方法之前开始了事务。你也可以直接自己做,使用UserTransaction,或者把用了调度器的代码放在一个使用容器的SessionBean里来管理事务。
12.
Plug-Ins
Quartz
装配给Quartz的Plugins能提供不同的有用的功能。在org.quartz.plugins包里有详细说明。他们提供的功能例如:调度器启动时自动调度jobs,记录job和triggers事件的历史,当JVM退出时确保调度器关闭。
可以通过配置属性文件来使用自己实现或Quartz自带的插件。
JobFactory
当一个trigger触发时,通过一个配置到调度器上的JobFactory,与trigger相关的job就被实例化了。默认的JobFactory会在job类上调用newInstance(),你可能想要创建自己的JobFactory实现来完成一些其他的事情,如:拥有应用程序的IoC或者DI容器进程/初始化job实例。
与Scheduler.setJobFactory(fact)方法联合起来察看org.quartz.spi.JobFactory接口,
Jobs工具
Quartz也提供一些有用的job,你能够用这些job来发邮件或者调用EJB。我们能在org.quartz.jobs包里找到它们。
13.配置文件里配置项总结
设置主要调度器
属性名
必须
类型
缺省值
org.quartz.scheduler.instanceName
no
string
'QuartzScheduler'
org.quartz.scheduler.instanceId
no
string
'NON_CLUSTERED'
org.quartz.scheduler.threadName
no
string
instanceName
org.quartz.scheduler.idleWaitTime
no
long
30000
org.quartz.scheduler.dbFailureRetryInterval
no
long
15000
org.quartz.scheduler.classLoadHelper.class
no
string
org.quartz.simpl.CascadingClassLoadHelper
org.quartz.context.key.SOME_KEY
no
string
none
org.quartz.scheduler.userTransactionURL
no
string
'java:comp/UserTransaction'
org.quartz.scheduler.wrapJobExecutionInUserTr
no
booelan
false
org.quartz.scheduler.jobFactory.class
no
string
org.quartz.simpl.SimpleJobFactory
org.quartz.scheduler.instanceName
任意的String,对于调度器自己并没有意义。但是当多个调度器实例用在一个程序里时,他就可以用来为客户端代码区别每个调度器。如果你用集群这个特性,你必须为在集群里的每个实例用一样的名字,实现逻辑上的一样的调度器。
org.quartz.scheduler.instanceId
任意的String,如果在一个集群里多个实例是一个逻辑上一样的调度器时,每个实例的这项属性必须唯一。你可以设置这项为“AUTO”从而自动收集ID。
org.quartz.scheduler.idleWaitTime
当调度器空闲时,在再次查询可用triggers之前,调度器将要等等待的毫秒数。正常情况下,我们不调整这个参数,除非我们用XA事务,或者在立即触发trigger时结果延误了。
org.quartz.scheduler.classLoadHelper.class
不需要更改。
org.quartz.context.key.SOME_KEY
设置org.quartz.context.key.MyKey
org.quartz.scheduler.userTransactionURL
是一个JNDI
org.quartz.scheduler.wrapJobExecutionInUserTr
设置这项为true使我们在调用job的execute()之前能够开始一个UserTransaction。在job的execute()完成之后,事务将会提交,并且,JobDataMap也更新了(是有状态的job)。
设置线程池
属性名
必须
类型
缺省值
org.quartz.threadPool.class
yes
string
null
org.quartz.threadPool.threadCount
yes
int
-1
org.quartz.threadPool.threadPriority
no
int
Thread.NORM_PRIORITY
org.quartz.threadPool.makeThreadsDaemons
no
boolean
false
org.quartz.threadPool.threadsInheritGroupOfIni
no
boolean
true
org.quartz.threadPool.threadsInheritContextCla
no
boolean
false
org.quartz.threadPool.class
通常使用org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadPriority
在
org.quartz.threadPool.makeThreadsDaemons、org.quartz.threadPool.threadsInheritGroupOfIni
如果用自己实现的线程池,可如下配置:
org.quartz.threadPool.class
org.quartz.threadPool.somePropOfFooThreadPool
设置全局监听器
全局监听器要有一个无参数的构造器,它的属性是通过反射设置的,仅支持简单数据和String。
Trigger监听器:
org.quartz.triggerListener.NAME.class
org.quartz.triggerListener.NAME.propName
org.quartz.triggerListener.NAME.prop2Name
job监听器:
org.quartz.jobListener.NAME.class
org.quartz.jobListener.NAME.propName
org.quartz.jobListener.NAME.prop2Name