一、序言
上篇文章Java下Spring实现Quartz集群分布式(一)的spring管理配置的xml文件的解析之一,为何需要配置红色字体的属性呢?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--<property name="applicationContextSchedulerContextKey" value="applicationContext"/>-->
<property name="jobFactory">
<bean class="wade.core.interceptors.SpringBeanJobFactory"/>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="configLocation" value="classpath:/conf/quartz.properties"/>
</bean>
</beans>
二、正文
1、假设我们要实现以下代码,即spring注入。
public class Task implements Job { @Autowired private AppServcie appServcie ; @Override public void execute(JobExecutionContext ctx) throws JobExecutionException { ... }
2、但是Job对象的实例化过程是在Quartz中进行的,AppServcie是在Spring容器当中的,那么如何将他们关联到一起呢。好在Quartz提供了JobFactory接口,让我们可以自定义实现创建Job的逻辑。
public interface JobFactory { Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException; }
3、 那么我们通过实现JobFactory 接口,在实例化Job以后,在通过ApplicationContext 将Job所需要的属性注入即可。在Spring与Quartz集成时 用到的是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类。源码如下,我们只看最关键的地方。
try {
this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
populateSchedulerContext();if (!this.jobFactorySet && !(this.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.jobFactory instanceof SchedulerContextAware) {
((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext());
}
this.scheduler.setJobFactory(this.jobFactory);
}
}
4、其中红色标记的是重点,如果我们不指定jobFactory,那么Spring就使用AdaptableJobFactory。我们在来看一下这个类的实现。
package org.springframework.scheduling.quartz;
import java.lang.reflect.Method;
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 {
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
return newJob(bundle);
}public Job newJob(TriggerFiredBundle bundle) throws SchedulerException {
try {
Object jobObject = createJobInstance(bundle);
return adaptJob(jobObject);
}
catch (Exception ex) {
throw new SchedulerException("Job instantiation failed", ex);
}
}protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
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();
}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.");
}
}}
5、其他的我们都不管,我们就看红色的地方,这里是创建了一个Job,那我们就在这里去给Job的属性进行注入就可以了,让我们写一个类继承它,然后复写这个方法进行对Job的注入。
package wade.core.interceptors; import org.quartz.spi.TriggerFiredBundle; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.AdaptableJobFactory; /** * <P><B>描述:</B> 自定义SpringBeanJobFactory,用于对Job注入ApplicationContext等。 </P> * * */ public class SpringBeanJobFactory extends AdaptableJobFactory { /** * The Application context. * * @see ApplicationContext */ private ApplicationContext applicationContext; /** * The Capable bean factory. */ @Autowired private AutowireCapableBeanFactory capableBeanFactory; /** * 日志记录. */ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SpringBeanJobFactory.class); @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { LOGGER.info("创建作业实体类"); //调用父类的方法 Object jobInstance = super.createJobInstance(bundle); //进行注入(这属于Spring的技术,不清楚的可以查看Spring的API) capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
6、接着就是最开始的配置到spring里 。
<property name="jobFactory">
<bean class="wade.core.interceptors.SpringBeanJobFactory"/>
</property>