Quartz的Job注入到Spring容器的实现过程
需要导入的pom
<!-- quartz --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency>
我想达到这样的效果
1.构建自定义Job,执行定时任务
//构建job信息 JobDetail jobDetail = JobBuilder .newJob(ExecutionJob.class) .withIdentity(JOB_NAME + quartzJob.getId()) .build(); //通过触发器名和cron 表达式创建 Trigger Trigger cronTrigger = newTrigger() .withIdentity(JOB_NAME + quartzJob.getId()) .startNow() .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression())) .build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//将job和trigger加入Scheduler中
scheduler.scheduleJob(jobDetail, cronTrigger);
2.自定义ExecutionJob类
@Async
@SuppressWarnings({"unchecked", "all"})
public class ExecutionJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
......
}
}
但是Job对象的实例化过程是在Quartz中进行的,ExecutionJob是在Spring容器当中的。
如何将他们关联到一起呢?Quartz提供了JobFactory接口,让我们可以自定义实现创建Job的逻辑。
public interface JobFactory { Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException; }
通过实现JobFactory 接口,在实例化Job以后,再通过ApplicationContext 将Job所需要的属性注入即可。
在Spring与Quartz集成时,用到的是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类。
源码如下,只看红色最关键的代码即可:
private Scheduler prepareScheduler(SchedulerFactory schedulerFactory) throws SchedulerException { ........
// Get Scheduler instance from SchedulerFactory. try { Scheduler scheduler = createScheduler(schedulerFactory, this.schedulerName); populateSchedulerContext(scheduler); if (!this.jobFactorySet && !(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.applicationContext != null && this.jobFactory instanceof ApplicationContextAware) { ((ApplicationContextAware) this.jobFactory).setApplicationContext(this.applicationContext); } if (this.jobFactory instanceof SchedulerContextAware) { ((SchedulerContextAware) this.jobFactory).setSchedulerContext(scheduler.getContext()); } scheduler.setJobFactory(this.jobFactory); } return scheduler; }
.......
}
意思是:如果我们不指定jobFactory,那么Spring就使用AdaptableJobFactory
再来看一下AdaptableJobFactory这个类的实现
package org.springframework.scheduling.quartz; import org.quartz.Job; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; import org.springframework.util.ReflectionUtils; public class AdaptableJobFactory implements JobFactory { @Override public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { try { Object jobObject = createJobInstance(bundle); return adaptJob(jobObject); } catch (Throwable ex) { throw new SchedulerException("Job instantiation failed", ex); } } protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Class<?> jobClass = bundle.getJobDetail().getJobClass(); return ReflectionUtils.accessibleConstructor(jobClass).newInstance(); } protected Job adaptJob(Object jobObject) throws Exception { if (jobObject instanceof Job) { return (Job) jobObject; } else if (jobObject instanceof Runnable) { return new DelegatingJob((Runnable) jobObject); } else { throw new IllegalArgumentException( "Unable to execute job class [" + jobObject.getClass().getName() + "]: only [org.quartz.Job] and [java.lang.Runnable] supported."); } } }
可以看见createJobInstance方法实例化了Job,但我想把Job注入到Spring中。
所以需要写一个类继承AdaptableJobFactory,然后重写createJobInstance方法实现对Job的注入。
@Component("quartzJobFactory") public static class QuartzJobFactory extends AdaptableJobFactory { private final AutowireCapableBeanFactory capableBeanFactory; public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) { this.capableBeanFactory = capableBeanFactory; } @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的方法,把Job注入到spring中 Object jobInstance = super.createJobInstance(bundle); capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
接下来set我的Job到JobFactory里,通过scheduler.start()开启定时器。
/** * 注入scheduler到spring * * @param quartzJobFactory * @return Scheduler * @throws Exception */ @Bean(name = "scheduler") public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception { SchedulerFactoryBean factoryBean = new SchedulerFactoryBean(); factoryBean.setJobFactory(quartzJobFactory); factoryBean.afterPropertiesSet(); Scheduler scheduler = factoryBean.getScheduler(); scheduler.start(); return scheduler; }
这样就完成了Job注入到Spring的功能,
原理就是扩展JobFactory创建Job的方法,启动Scheduler之后将Scheduler注入到Spring。
代码地址:https://github.com/SuPiaoPiao/spring_quartz.git