spring3.2.0 quartz-2.2.1 实现动态定时任务
spring 和 quartz的整合很简单,但是实现动态定时任务却有一点麻烦,下面详细介绍一下 spring3.2.0和quzrtz2.2.1 的整合 实现定时任务的的动态加载
项目整体结构介绍:
需要的jar以及整体结构如下
类介绍:
AutoJobDTO.java 里面就是一些job的信息,jobname groupname等;JobAction.java 自动任务调度;JobManager.java 任务的管理(新增,删除,暂停等 这里举例新增的,其余的可以看官网API)JobService.java 动态造数据,调用
JobManager 添加任务;
quartz 中的 job如何自动注入spring容器托管的对象?MyJobFactory.java
这个类可以为大家说明;
TestService.java 这个类就用来测试一下注入;
源代码:
AutoJobDTO.java
package quartz;
/**
* 任务信息
* @author Administrator
*
*/
public class AutoJobDTO {
private String job_id;
private String job_name;
private String job_group;
private String job_time; {get set ....}
package quartz;
import javax.annotation.Resource;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
//@DisallowConcurrentExecution//有状态的任务需要加上这个注解
public class JobAction implements Job {
@Autowired
private TestService testService;
{get set ...}
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("任务成功运行------");
AutoJobDTO detailInfo = (AutoJobDTO)arg0.getMergedJobDataMap().get("scheduleJob");
System.out.println("任务名称 = [" + detailInfo.getJob_name()+ "]");
if(testService==null){
System.out.println("注入不成功------");
}else{
System.out.println("注入成功------");
testService.add();
}
}
}
JobManager.action
package quartz;
import java.text.ParseException;
import javax.annotation.Resource;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
public class JobManager {
/* 当初我初始化的是 SchedulerFactoryBean schedulerFactoryBean; 这样是注入不进去的 报下面的错
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'schedulerFactoryBean' must be of
type [org.springframework.scheduling.quartz.SchedulerFactoryBean],
but was actually of type [org.quartz.impl.StdScheduler>]
看spring源码可以知道,其实spring得到的是一个工厂bean,得到的不是它本身,而是它负责创建的org.quartz.impl.StdScheduler对象 所以要使用Scheduler对象
*/
@Resource
private Scheduler scheduler ;
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
/**
* 添加一个定时任务
*/
public void addJob(AutoJobDTO job,Class classz) throws SchedulerException {
//这里获取任务信息数据
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJob_name(), job.getJob_group());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(trigger==null){
System.out.println("trigger is null----");
//不存在,创建一个
JobDetail jobDetail = JobBuilder.newJob(classz).withIdentity(job.getJob_name(), job.getJob_group()).build();
jobDetail.getJobDataMap().put("scheduleJob", job);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getJob_time());
//按新的cronExpression表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(job.getJob_name(), job.getJob_group()).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,trigger);
}else{
// Trigger已存在,那么更新相应的定时设置
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getJob_time());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
}
/**
* 启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
package quartz;
import javax.annotation.Resource;
import org.quartz.SchedulerException;
/**
* 调用job
* @author Administrator
*
*/
public class JobService {
@Resource
private JobManager jobManager;
public JobManager getJobManager() {
return jobManager;
}
public void setJobManager(JobManager jobManager) {
this.jobManager = jobManager;
}
/**
* 初始化定时任务
* @throws SchedulerException
*/
public void loadJobInit() throws SchedulerException{
System.out.println("init---");
AutoJobDTO job = new AutoJobDTO();
job.setJob_id("Id1");
job.setJob_name("Name1");
job.setJob_group("linGroup");
job.setJob_time("0/30 * * * * ?");
jobManager.addJob(job, JobAction.class);
jobManager.startJobs();
}
}
TestService.javapackage quartz;
public class TestService {
public void add(){
System.out.println("注入测试----");
}
}
MyJobFactory.java
这个类是重写 AdaptableJobFactory 的createJobInstance这个方法,具体原因参见:
http://blog.youkuaiyun.com/linlinv3/article/details/49450775
package spring;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
public class MyJobFactory extends AdaptableJobFactory {
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
或者这么写也可以,因为有情况说上述方法打包后 注入不进去
package com.summoner.service.job.impl;
import javax.annotation.Resource;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
public class MyJobFactory extends AdaptableJobFactory implements ApplicationContextAware {
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
// @Resource
// private AutowireCapableBeanFactory capableBeanFactory;
ApplicationContext applicationContext;
// public AutowireCapableBeanFactory getCapableBeanFactoryYunZong() {
// return capableBeanFactoryYunZong;
// }
//
//
// public void setCapableBeanFactoryYunZong(
// AutowireCapableBeanFactory capableBeanFactoryYunZong) {
// this.capableBeanFactoryYunZong = capableBeanFactoryYunZong;
// }
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
AutowireCapableBeanFactory aaa = applicationContext.getAutowireCapableBeanFactory();
aaa.autowireBeanProperties(jobInstance, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
// applicationContext.getAutowireCapableBeanFactory().autowireBean(jobInstance);
// capableBeanFactoryYunZong.autowireBean(jobInstance);
return jobInstance;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
spring 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
>
<context:component-scan base-package="quartz" />
<bean id="testService" class="quartz.TestService"></bean>
<bean id="jobFactory" class="spring.MyJobFactory"></bean>
<bean id="Scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="jobFactory" />
</bean>
<bean id="jobManager" class="quartz.JobManager"> </bean>
<bean id="JobService" class="quartz.JobService" init-method="loadJobInit"></bean>
</beans>
然后启动程序就能看到定时任务的加载,console输出