最近在项目中遇到了定时对账的需求,本来是打算用Timer来着,后来因为考虑到需求可能会进一步细化,比如从最初的每日一对变为每小时一对等等,觉得还是使用相对成熟的框架quartz比较好。下面就自己的使用过程中的一些经验做一些简单记录。
1. 在maven的pom.xml文件里面添加quartz的包依赖
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-oracle</artifactId>
<version>1.8.0</version>
</dependency>
然后mvn install,下载相应的包
2. 在src/main/resouces下面添加quartz.properties文件。
配置文件的详细配置就不说了,值得一提的是在配置文件里面加入了对任务持久化的
支持:
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.HSQLDBDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=XXX
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=15000
3. 在spring的配置文件里面配置任务bean.
首先说一下quartz实现定时任务的方式。quartz暴露给用户的角色大概有三个: Scheduler,Trigger,Task.
Task就是要实现的任务,自定义的task需要实现QuartzJobBean接口。Trigger是触发器,通过制定特定的触发条件来 触发task;Scheduler是一个调度器,功能就是把触发器和任务绑定在一起。当然Trigger自身也可以有Job参数。同时,Scheduler还可以在运行时动态对task进行调度。
下面就是我配置的一个调度:
<bean id="a" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>
com.××
</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="c">
<ref bean="C" />
</entry>
</map>
</property>
</bean>
<bean id="b"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<ref bean="a" />
</property>
<property name="startDelay">
<value>9100</value>
</property>
<property name="repeatInterval">
<value>9100</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="startupDelay" value="30"/>
<property name="triggers">
<list>
<ref local="b" />
</list>
</property>
</bean>
这样,只需要在任务里面写自己的业务代码就可以了。
另外,我尝试了一下,按这种方式配置多个scheduler的情况下,如果在quartz.properties配置了线程池
org.quartz.threadPool.threadCount = 8,那么每个scheduler都可以有8个单独的线程运行任务。
但是在当前项目中,出于同步考虑,我希望每次只有一个线程在运行这个job.所以每个job都实现了StatefulJob接口,
这个接口的意义如下:
/**
* <p>
* A marker interface for <code>{@link org.quartz.JobDetail}</code> s that
* wish to have their state maintained between executions.
* </p>
*
* <p>
* <code>StatefulJob</code> instances follow slightly different rules from
* regular <code>Job</code> instances. The key difference is that their
* associated <code>{@link JobDataMap}</code> is re-persisted after every
* execution of the job, thus preserving state for the next execution. The
* other difference is that stateful jobs are not allowed to execute
* concurrently, which means new triggers that occur before the completion of
* the <code>execute(xx)</code> method will be delayed.
大抵看来,就两个作用。
1. 在job的执行过程中保持JobDataMap里面的对象的状态,使得里面的对象在每一次执行过后都预持久化,以供
下一次执行使用
2. 防止多个线程同时执行某一job.