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);

//将jobtrigger加入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

 

posted @ 2021-06-30 12:47  素净  阅读(1385)  评论(0编辑  收藏  举报