Springcloud学习笔记67--springboot 整合 任务调度框架Quartz
1.背景
定时任务Job的作业类中无法注入Service等由Spring容器所管理的Bean。例如下面这种情况,TaskCronJobService就无法成功注入。
import java.util.Iterator; import javax.annotation.Resource; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; import com.pengjunlee.task.bean.TaskCronJob; import com.pengjunlee.task.service.TaskCronJobService; /** * 定时任务的作业类,需实现Job接口 * */ @Component public class MyJob implements Job { @Resource private TaskCronJobService taskCronJobService; @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { System.out.println("执行定时任务:MyJob.execute()..." + System.currentTimeMillis()); Iterable<TaskCronJob> findAll = taskCronJobService.findAll(); Iterator<TaskCronJob> iterator = findAll.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().getJobClassName()); } } }
定时任务Job对象的实例化过程是在Quartz中进行的,而TaskCronJobService Bean是由Spring容器管理的,Quartz根本就察觉不到TaskCronJobService Bean的存在,故而无法将TaskCronJobService Bean装配到Job对象中。
知道了问题出现的原因,解决的办法也就显而易见了:如果能够将Job Bean也纳入到Spring容器的管理之中的话,Spring容器自然能够为Job Bean自动装配好所需的依赖。
通过查看Spring官方文档得知,Spring与Quartz集成使用的是SchedulerFactoryBean这个类,其所需引入Maven依赖如下。
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <!-- 该依赖必加,里面有sping对schedule的支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
以下是SchedulerFactoryBean类(spring-context-support 这个包)的部分关键代码。
package org.springframework.scheduling.quartz; public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBean<Scheduler>, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, SmartLifecycle { @Override public void afterPropertiesSet() throws Exception { //---------------------------省略部分代码-------------------------- // Get Scheduler instance from SchedulerFactory. try { this.scheduler = createScheduler(schedulerFactory, this.schedulerName); populateSchedulerContext(); if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) { // Use AdaptableJobFactory as default for a local Scheduler, unless when // explicitly given a null value through the "jobFactory" bean property. this.jobFactory = new AdaptableJobFactory(); } if (this.jobFactory != null) { if (this.jobFactory instanceof SchedulerContextAware) { ((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext()); } this.scheduler.setJobFactory(this.jobFactory); } } //---------------------------省略部分代码-------------------------- } }
从以上代码可以看出:SchedulerFactoryBean 使用 AdaptableJobFactory 对Job对象进行实例化,如果未指定则SchedulerFactoryBean会自动创建一个,在这里如果我们能够将 SchedulerFactoryBean 的 jobFactory 指定为我们自定义的工厂实例的话,我们就能够有机会在Job实例化完成之后对其进行处理,并将其纳入到Spring容器的管理之中。
2. springboot整合quartz实践
例如下面这段代码,创建一个SchedulerFactoryBean 实例,并将其Job实例化的工厂指定为一个Spring容器中一个自定义的 TaskSchedulerFactory 实例。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.SchedulerFactoryBean; @Configuration public class QuartzConfig { @Autowired private QuartzJobFactory jobFactory; @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(jobFactory); return schedulerFactoryBean; } @Bean public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } }
Quartz为我们提供了一个JobFactory接口,允许我们自定义实现创建Job的逻辑。
package org.quartz.spi; public interface JobFactory { Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException; }
AdaptableJobFactory 就是 Spring 为我们提供的一个该接口的实现类,提供了创建Job实例的基本方法。
自定义的工厂类 QuartzJobFactory 只需要继承 AdaptableJobFactory ,通过调用父类 AdaptableJobFactory 的方法来实现对Job的实例化,在Job实例化完以后,再调用自身方法为创建好的Job实例进行属性自动装配并将其纳入到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; import org.springframework.stereotype.Component; @Component public class QuartzJobFactory extends AdaptableJobFactory { // 需要使用这个BeanFactory对Qurartz创建好Job实例进行后续处理,属于Spring的技术范畴. @Autowired private AutowireCapableBeanFactory capableBeanFactory; protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { // 首先,调用父类的方法创建好Quartz所需的Job实例 Object jobInstance = super.createJobInstance(bundle); // 然后,使用BeanFactory为创建好的Job实例进行属性自动装配并将其纳入到Spring容器的管理之中,属于Spring的技术范畴. capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
参考文献:
https://blog.csdn.net/pengjunlee/article/details/78965877 (SpringBoot重点详解--如何为Quartz的Job自动装配Spring容器Bean)
https://blog.csdn.net/qq_43419029/article/details/92659690