Quartz中给自定义Job类注入对象异常的解决办法

在使用Quart定时任务框架时,自定义Job类不支持@Autowired。往Job任务类中注入对象后,通过注入对象调用方法发现,运行出现异常。原来,并没有注入成功!

JobDetailFactoryBeansetJobClass()方法底层调用的是AdaptableJobFactorycreateJobInstance()方法。该方法是通过反射创建的对象。
看源码:

 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Class<?> jobClass = bundle.getJobDetail().getJobClass();
        return ReflectionUtils.accessibleConstructor(jobClass, new Class[0]).newInstance();//反射创建对象
 }

也就是说,这时候创建我们自定义的Job类时并没有用到spring容器。即spring容器中没有我们的Job类对象。
而spring的依赖注入要求注入对象和被注入对象都要在容器中,所以当我们在给Job类注入对象时是注入不成功的!
那怎么解决呢?

解决思路
我们可以写一个类继承AdaptableJobFactory并重写createJobInstance方法,创建完对象后我们手动地给他放到spring容器中

---------------------------------------这是一条华丽的分割线-------------------------------------------

先来看看我的Job类。
定时任务的Job:
给自定义Job类注入对象(TestService)。能注入成功吗?不能!为什么?

public class MyJob implements Job {
    //给Job注入对象(TestService)。能成功吗?不能!为什么?
    @Autowired
    private TestService testService;
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
        System.out.println("  定时任务:" + printTime + "开始, prints: Hello Job-" + new Random().nextInt(100));
        testService.addUser();//调用注入对象的方法
    }
}

Quartz配置类:

@Configuration
public class QuartzConfig {
    //1.配置JobDetail任务对象
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        //关联自己的job类
        factoryBean.setJobClass(MyJob.class);
        return factoryBean;
    }
    
    //2.配置Trigger触发器 。略
    //3.配置Scheduler调度器 。略

解决:
写一个类继承AdaptableJobFactory并重写createJobInstance方法

@Component
public class MyAdaptableJobFactory extends AdaptableJobFactory {
    // AutowireCapableBeanFactory就可以将一个对象添加到spring容器中,并且完成该对象的属性注入。
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;
    /**
     *  该方法需要将实例化的任务对象手动地添加到spring容器中并完成对象的注入
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception{
        Object obj = super.createJobInstance(bundle);
        //将obj对象添加到spring容器中并完成属性注入
        autowireCapableBeanFactory.autowireBean(obj);
        return obj;
    }
}

Quartz配置: 配置调度器时传入我们刚刚写的类MyAdaptableJobFactory

	//前几步代码.略
	//3.配置Scheduler调度器
	//给
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean,MyAdaptableJobFactory myAdaptableJobFactory){
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        //关联trigger
        factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
        factoryBean.setJobFactory(myAdaptableJobFactory);//重新设置创建Job实例的工厂类
        return factoryBean;
    }

这样就可以完成属性注入啦!!!!

但是感觉这样有点麻烦,我完全可以把我写这个类在Quartz配类里配置,这样一个文件就搞定了。
优化:Quartz配置

/**
 * Quartz配置类
 */
@Configuration
public class QuartzConfig {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 扩展SpringBeanJobFactory,使Job实现类支持@autowired注入
     */
    private final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;
        @Override
        public void setApplicationContext(final ApplicationContext context) {
            beanFactory = context.getAutowireCapableBeanFactory();
        }
        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            beanFactory.autowireBean(job);
            return job;
        }
    }
    //1.配置JobDetail任务对象
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        //关联自己的job类
        factoryBean.setJobClass(PrintWordsJob.class);
        return factoryBean;
    }
    //2.配置Trigger触发器
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //设置时间
        factoryBean.setCronExpression("0/2 * * * * ?");//每两秒触发一次

        return factoryBean;
    }

    //3.配置Scheduler调度器
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean){
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        //关联trigger
        factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
        AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory = new AutowiringSpringBeanJobFactory();
        factoryBean.setJobFactory(autowiringSpringBeanJobFactory);
        return factoryBean;
    }

    /*配置完了怎么启动呢?给springboot启动类加@EnableShceduling注解*/
}

---------------------天大寒,砚冰坚,手指不可屈伸,弗之怠。--------------------------

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值