quartz的實現流程
阿新 • • 發佈:2021-06-30
需要匯入的pom
<!-- quartz --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency>
我想達到這樣的效果
public class ExecutionJobTask implements Job {
@Autowired
private QuartzJobService quartzJobService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//執行我的方法
quartzJobService .xxx();
......
}
}
但是Job物件的例項化過程是在Quartz中進行的,AppOrderService是在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 { if (this.resourceLoader != null) { // Make given ResourceLoader available for SchedulerFactory configuration.configTimeResourceLoaderHolder.set(this.resourceLoader); } if (this.taskExecutor != null) { // Make given TaskExecutor available for SchedulerFactory configuration. configTimeTaskExecutorHolder.set(this.taskExecutor); } if (this.dataSource != null) { // Make given DataSource available for SchedulerFactory configuration. configTimeDataSourceHolder.set(this.dataSource); } if (this.nonTransactionalDataSource != null) { // Make given non-transactional DataSource available for SchedulerFactory configuration. configTimeNonTransactionalDataSourceHolder.set(this.nonTransactionalDataSource); } // 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; } finally { if (this.resourceLoader != null) { configTimeResourceLoaderHolder.remove(); } if (this.taskExecutor != null) { configTimeTaskExecutorHolder.remove(); } if (this.dataSource != null) { configTimeDataSourceHolder.remove(); } if (this.nonTransactionalDataSource != null) { configTimeNonTransactionalDataSourceHolder.remove(); } } }
意思是說:如果我們不指定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方法例項化了JobClass,但我想把JobClass注入到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; } }
接下來注入我自己的Job到JobFactory裡
/** * 注入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的方法,在建立完Job以後進行屬性注入。