quartz定时任务service注入失败的详细的原因我查了查是这样的:
Job是在quartz的框架中实例化的,service是在spring容器中创建出来的,所以Job实现类不受spring管理,即导致注入失败,所以要想解决这个问题就需要,将他们关联起来。好在Quartz提供了JobFactory接口,就可以自定义实现创建Job的逻辑。就像这样:
public interface JobFactory { Job newJob(TriggerFiredBundle var1, Scheduler var2) throws SchedulerException; }
这个接口所处的位置就是我们在maven引入的Quartz Jar包,是quartz包里面的一个接口,我们通过实现JobFactory接口,在实例化Job以后,在通过ApplicationContext将Job所需要的属性注入即可。
在Spring与Quartz集成时,用到的是SchedulerFactoryBean这个类,这个类是spring-context-support里面的一个类,源码里面有这么一句话(源码很长,我也不会一一解读,很多其实也看不懂,但截取了其中涉及到的一段):
this.scheduler = this.createScheduler(schedulerFactory, this.schedulerName); this.populateSchedulerContext(); if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) { 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); }
这段代码解释是这样的,如果我们不指定JobFactory,那么spring就使用AdaptableJobFactory,这个类就是JobFactory的实现类,AdaptableJobFactory的不分源码如下:
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Method getJobDetail = bundle.getClass().getMethod("getJobDetail"); Object jobDetail = ReflectionUtils.invokeMethod(getJobDetail, bundle); Method getJobClass = jobDetail.getClass().getMethod("getJobClass"); Class jobClass = (Class)ReflectionUtils.invokeMethod(getJobClass, jobDetail); return jobClass.newInstance(); }此处创建了一个Job实例,那我们就在这里去给Job的属性进行注入就可以了,然后我们就写一个类来继承他,并重写这个方法对Job进行注入。如下:
public class MyJobFactory extends AdaptableJobFactory { @Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的方法 Object jobInstance = super.createJobInstance(bundle); //进行注入,这属于Spring的技术,不清楚的可以查看Spring的API. autowireCapableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
然后把他配置到spring当中去,参考前一篇文章里面xml的配置里面的一句话。
<bean id="jobFactory" class="com.gao.ssm.module.quartz.MyJobFactory"/>
然后把SchedulerFactoryBean的JobFactory设置成我们自己的。
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobFactory" ref="jobFactory"/> <!--其他属性值省略--> </bean>
这样就完成了Spring对Job的注入功能,原理就是在我们扩展JobFactory创建Job的方法,在创建完Job以后进行属性注入。
跟上面的分析我自己集合类所在jar包整理了一下,我觉得观察上面的类所在的jar就更容易理解,job如何自动注入spring容器托管的对象 。
(说明:本文是我参照另一篇文章 为加深理解自己敲了一遍,读者也可以直接读原文。)