Quartz初步接触
1.pom引入
指定版本
<quartz.version>2.2.2</quartz.version>
引入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
2.配置spring
<context:component-scan base-package="com.wx.app.sgp.task" />
<!--扩展Quartz Job中spring的自动注入 -->
<bean id="jobFactory" class="com.wx.app.sgp.task.MyJobFactory"></bean>
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="jobFactory"></property>
</bean>
3.初始化任务列表
做法是在容器初始化时读取mysql中存储的任务信息,利用的是ApplicationListener(初始化spring完成后就会触发这个事件,这个以后有机会再写一篇关于如何在项目初始化加载时进行某些操作的文章)
@Component
public class InstantiationTracingBeanPostProcessor implements ApplicationListener<ContextRefreshedEvent> {
...
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)
if(event.getApplicationContext().getParent() == null){ //root application context 没有parent,他就是老大.
//需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
log.debug("初始化任务配置");
initAllJobs();
} else {
}
}
...
private void initAllJobs(){
//这里就写初始化逻辑了
//定义Task对象与数据库存储记录对应(主要是记录任务的唯一性group,name及最重要的时间表达式)
//定义ScheduleJob 对象,主要是将task转换成需要的任务对象,这里做了一个枚举,为了打日志用的,这个对象可以不要
//然后将任务注册
public void newOrUpdateJob(ScheduleJob job) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//不存在,创建一个
if (null == trigger) {
JobDetail jobDetail =
JobBuilder.newJob(QuartzJobFactoryImpl.class).withIdentity(job.getJobName(), job.getJobGroup()).build();
jobDetail.getJobDataMap().put("scheduleJob", job);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder =
CronScheduleBuilder.cronSchedule(job.getCronExpression());
//按新的cronExpression表达式构建一个新的trigger
trigger =
TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} else {
// Trigger已存在,那么更新相应的定时设置
//表达式调度构建器
CronScheduleBuilder scheduleBuilder =
CronScheduleBuilder.cronSchedule(job.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger =
trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
}
}
Quartz注册任务需要JobDetail对象和CronTrigger对象,而JobDetail需要name、group属性,CronTrigger需要时间表达式,有这三个属性其实已经可以注册一个任务了,当然也可以提交一任务相关的data保存在Quartz任务对象里的map里,剩下执行任务则交给Quartz去完成了。到这里初始化注册任务完成了。
4.实现任务工厂,autowrite bean
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
5.自定义一个任务
这里可以定义个接口RunJob,里面写个方法runJob
每个具体的业务逻辑可以新建一个service实现RunJob.runJob。
目的就是为了下面接口代理,少写点代码。
6.所有的都写完了,是时候去执行一下任务了。
新建个工厂类,继承Job,重写execute方法
这里主要是从注册的任务列表中获取要执行的任务去执行,顺便写点日志,代码就不贴了
补充:Quartz时间表达式可以去百度一下,我这里有一份但是是别的小哥,没有和他联系我就不贴了。
总结:
主要的思路就是通过mysql实现job的可配置化,然后启动任务,quart计算时间执行任务,通过mysql中的信息与加载的自定义任务bean的关系(定义个id,或者直接用name,group去确定)获取要执行的bean的引用,通过接口代理执行被代理的任务runJob方法