quartz(开源项目)
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
1.1. Quartz开发步骤说明
1)创建任务 – Job 你要干什么?
2)创建触发器-Trigger 要什么时候做?
3)创建任务调度-Scheduler 什么时候干什么?
1.2. 创建Quartz的Java应用
1.2.1. 导入quartz的坐标
<dependencies> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.2</version> </dependency> </dependencies>
1.2.2. 定义Job对象
/** * 自定义Job * @author lenovo * */ public class TestJob implements Job{ //execute:一旦任务触发,就会执行此方法 @Override public void execute(JobExecutionContext context) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("任务被触发:"+sdf.format(new Date())); } }
1.2.3. 编写任务调用测试类
Quartz分内简单触发器和日历触发:
简单触发器(SimpleTrigger):主要完成固定重复地任务(按照秒,分,小时)来重复。(例如,每隔30分钟做事件)
日历触发器(CronTrigger): 主要可以按照日历的形式进行重复地任务。(例如:每个星期的一,三,五晚上12点做事情)(常用)
1.2.3.1. 编写简单触发器版本
/** * 简单触发器案例 * @author lenovo * */ public class SimpleTriggerDemo { public static void main(String[] args) throws Exception { //1)创建任务 - Job 你要干什么? JobDetail job = JobBuilder .newJob(TestJob.class) .build(); //2)创建触发器-Trigger 要什么时候做? Trigger trigger = TriggerBuilder .newTrigger() .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3)) .build(); //3)创建任务调度-Scheduler 什么时候干什么? Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //建立job和trigger的关系 scheduler.scheduleJob(job, trigger); //4)启动任务 scheduler.start(); } }
1.3. 创建CronTrgger日历触发器(比较常用)
按照日历规则进行重复。例如 每个1,3,5进行重复。
/** * 日历触发器案例 * */ public class CronTriggerDemo { public static void main(String[] args) throws Exception { //1)创建任务 - Job 你要干什么? JobDetail job = JobBuilder .newJob(TestJob.class) .build(); //2)创建触发器-Trigger 要什么时候做? Trigger trigger = TriggerBuilder .newTrigger() //传入cron表达式(日历表达式) .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *")) .build(); //3)创建任务调度-Scheduler 什么时候干什么? Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //建立job和trigger的关系 scheduler.scheduleJob(job, trigger); //4)启动任务 scheduler.start(); } }
1.4. cron表达式的语法
CronScheduleBuilder.cronSchedule("0/5 * * * * ? *")
2. Spring整合Quartz框架
2.1. 导入quartz和spring的坐标
quartz的坐标:
<!-- quartz任务调度 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
spring的坐标:
spring整合quartz的API的spring-context-support
<!-- spring-context-support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
2.2. 编写Job任务类
/**
* 自定义Job
* @author lenovo
*
*/
public class TestJob implements Job{
//execute:一旦任务触发,就会执行此方法
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("任务被触发:"+sdf.format(new Date()));
}
}
2.3. 编写applicationContext-quartz.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Spring整合Quartz --> <!-- 1.创建JobDetail --> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 关联我们的Job类 --> <property name="jobClass" value="com.fyc.bos.jobs.TestJob"/> </bean> <!-- 2.创建Trigger:SimpleTriiger --> <bean id="trigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <!-- 关联JobDetail --> <property name="jobDetail" ref="jobDetail"/> <!-- 间隔时间 (毫秒)--> <property name="repeatInterval" value="3000"></property> <!-- 重复次数 --> <property name="repeatCount" value="4"></property> </bean> <!-- 3.创建Scheduler --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- 关联trigger --> <property name="triggers"> <list> <ref bean="trigger"/> </list> </property> </bean> </beans>
导入xml:
<import resource="classpath:applicationContext-quartz.xml"/>
2.4. CronTrigger配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Spring整合Quartz --> <!-- 1.创建JobDetail --> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 关联我们的Job类 --> <property name="jobClass" value="com.fyc.bos.jobs.TestJob"/> </bean> <!-- 2.创建Trigger:SimpleTriiger --> <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- 关联JobDetail --> <property name="jobDetail" ref="jobDetail"/> <!-- cron表达式 --> <property name="cronExpression" value="0/5 * * * * ? *"/> </bean> <!-- 3.创建Scheduler --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- 关联trigger --> <property name="triggers"> <list> <ref bean="trigger"/> </list> </property> </bean> </beans>
我的实际项目中的使用
导入的maven依赖
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.2</version> </dependency> //其它的依赖略
要触发的实际执行的类
这里是根据现在的时间和数据库的实际比较进行的跟新操作。后面的逻辑代码就不贴出了。
public class PromotionJob implements Job { @Resource private PromotionService promotionService; @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //结束时间是否小于系统时间,如果是的话,自动更新status,改为0。 //System.out.println("PromotionJob任务被触发..."); promotionService.updateStatus(new Date()); } }
配置信息
applicationContext-quartz.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 关联我们的Job类 --> <property name="jobClass" value="com.fyc.bos.jobs.PromotionJob"/> <!-- 2.创建Trigger:SimpleTriiger --> </bean> <!-- 2.创建Trigger:SimpleTriiger --> <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- 关联JobDetail --> <property name="jobDetail" ref="jobDetail"/> <!-- cron表达式 5秒测试一次--> <property name="cronExpression" value="0/5 * * * * ? *"/> </bean> <!-- 3.创建Scheduler --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- 覆盖setJobFactory ,使用我们自定义的JobFactory--> <property name="jobFactory" ref="jobFactory"/> <!-- 关联trigger --> <property name="triggers"> <list> <ref bean="trigger"/> </list> </property> </bean> </beans>
记得把这份配置导入到spring的主配置中
<import resource="applicationContext-quartz.xml"/>
上面的配置我由于是先测试使用了每五秒做为一次更新。这个日历更新的频率要根据你实际的项目需求去修改
上面的<property name="jobFactory" ref="jobFactory"/>没有添加这个自己注入到的spring对象会出现无法注入PromotionService对象。
在Job对象无法注入Spring对象的问题
原因:Spring框架整合了quartz整合,在创建JobDetail对象的过程中,使用AdapterJobFactory的createJobInstance这个方法去创建JobDetail对象的:
通过查看源码,我们发现Spring在创建JobDetail只是用了反射代码直接创建了对象,而没有把该对象放入Spring的IOC容器管理,所以无法在该对象中注入其他Spring对象。
解决办法:手动把JobDetail对象放入SpringIOC容器中。
设计一个JobFactory:
/* * 自定义JobFactory对象,重写createJobInstance方法 */ @Component public class MyJobFactory extends AdaptableJobFactory { @Resource private AutowireCapableBeanFactory factory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的原有的方法创建JobDetail对象 Object jobDetail = super.createJobInstance(bundle); //把JobDetail放入SpringIOC容器中管理 factory.autowireBean(jobDetail); return jobDetail; } }