了解过Quartz的同学可能会知道,在Quartz的默认配置中,执行的Job只是简单的调用job类的newInstance()方法来创建Job实例,这种方式执行的Job有时候并不能满足我们的需求,比如无法注入容器产生的实例。
在Spring项目中我们可能并不会过于关注Quartz,因为一些常见的问题(包含上面提到的注入)Spring已经帮我们处理好,如果你在非Spring项目中,集成Quartz后需要注入容器实例,那么这篇文章应该会对你有所帮助(文章不做Quartz的入门介绍)。
在Quartz的文档中,有这么一段描述:
JobFactory
当trigger触发时,通过Scheduler上配置的JobFactory实例化与之关联的jobs。
默认的JobFactory只是在jobs类上调用newInstance()。
您可能需要创建自己的JobFactory实现,
以完成诸如让应用程序的IoC或DI容器生成/初始化jobs实例之类的操作。
请参阅org.quartz.spi.JobFactory接口以及
相关的Scheduler.setJobFactory(fact) 方法。
这段话告诉我们默认的JobFactory(参考SimpleJobFactory类)只是在job类上调用newInstance()方法,我们如果想自定义类实例,可以自己去实现JobFactory,但并不是我们对JobFactory接口进行实现,实现类就会负责初始化Job实例的工作。
这里先这里给出解决方案:
上面的步骤中,相对于JobFactory接口的实现,更重要的一步是如何使JobFactory生效,下面具体分析如何实现。
在org.quartz.Scheduler接口中,有setJobFactory方法
void setJobFactory(JobFactory var1) throws SchedulerException;
由此可见,要想完成这一功能就需要在setJobFactory这里出发,在StdSchedulerFactory创建Scheduler的工厂类中,创建 JobFactory最核心的一步就是获取jobFactoryClass,
this.cfg.getStringProperty("org.quartz.scheduler.jobFactory.class",
cfg实际上配置文件的数据,读取后放到PropertiesParser对象中,在StdSchedulerFactory工厂类创建Scheduler的时候,会读取配置key为 org.quartz.scheduler.jobFactory.class的数据,如果读取不到那么默认为null,此时就会使用默认的JobFactory,所以我们要做的工作就是让其读取到,不走默认的JobFactory。
这里说的配置文件在Quartz源码中也默认有一份,但是该配置文件并未并未设置org.quartz.scheduler.jobFactory.class,所以我们需要自己去写一个配置文件(也可以不使用配置文件,因为初始化配置的方式有三种,这里我选用的是配置文件)
配置文件:
org.quartz.scheduler.jobFactory.class:quartz.JobFactoryAdapt
配置好之后,就需要让工厂类读取这个配置了,在StdSchedulerFactory工厂类中,提供了三个不同参数的initialize方法来设置配置文件(配置文件路径,文件流,直接构造Properties对象),下面代码红色字体即初始化配置过程。
StdSchedulerFactory stdSchedulerFactory =
到这里配置就会生效,Quartz生成需要执行Job的就会走我们自定义的JobFactory。在Quartz中JobFactory的设计,为我们实现自定义功能留了扩展的可能。
最后工厂类的实现就相对简单了,在返回实例前,通过上下文对需要注入的字段进行注入。
项目地址:https://github.com/xynuSuMu/jerry.git
public class JobFactoryAdapt implements JobFactory {
//
private JerryContext jerryContext = JerryContext.getInstance();
@Override
public Job newJob(TriggerFiredBundle triggerFiredBundle, Scheduler scheduler) throws SchedulerException {
return newJob(triggerFiredBundle);
}
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 {
Method getJobDetail = bundle.getClass().getMethod("getJobDetail");
Object jobDetail = getJobDetail.invoke(bundle);
Method getJobClass = jobDetail.getClass().getMethod("getJobClass");
Class jobClass = (Class) getJobClass.invoke(jobDetail);
//为字段赋值
Object o = jobClass.newInstance();
Field[] fields = jobClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.get(o) == null) {
Object proxy = jerryContext.getBean(field.getType().getName());
if (proxy != null)
field.set(o, proxy);
}
}
return o;
}
protected Job adaptJob(Object jobObject) throws Exception {
return (Job) jobObject;
}
}