也许这篇文章的名字应该改成《Quartz JobFactory的使用》,因为正是使用JobFactory解决的Quartz Job类有参数构造方法的问题。同样,使用JobFactory也能解决Job已有实例重用的问题。
问题如标题描述:就是希望为Job类的实例传递参数,结果发现找到的文档中创建Job实例的方法多是通过类反射来实现的,这显然不能满足我的需求。
也找到了一些文章建议使用jobDataMap来解决。不太喜欢这种方案,因为太难看了——只是搬个砖而已,却连底裤都漏出来了。
翻了下官方文档,在 Lesson 12: Miscellaneous Features of Quartz 这一节找了关于 JobFactory 的描述,虽然寥寥几行,却指明了解决问题的方向。
JobFactory,根据文档描述,是 Scheduler 的一个配置项,主要用来完成Job实例的注入。默认使用的JobFactory只是简单地调用了Job 类的newInstance()方法来创建了实例。
要解决我的问题需要创建自定义的JobFactory实现。JobFactory的实现可以参考默认JobFactory的实现 SimpleJobFactory 的一些代码:
public Job newJob(TriggerFiredBundle bundle, Scheduler Scheduler) throws SchedulerException {
JobDetail jobDetail = bundle.getJobDetail();
Class<? extends Job> jobClass = jobDetail.getJobClass();
try {
if(log.isDebugEnabled()) {
log.debug(
"Producing instance of Job '" + jobDetail.getKey() +
"', class=" + jobClass.getName());
}
return jobClass.newInstance();
} catch (Exception e) {
SchedulerException se = new SchedulerException(
"Problem instantiating class '"
+ jobDetail.getJobClass().getName() + "'", e);
throw se;
}
}
相当简单的内容,只需要在创建实例那块儿填写自定义的内容就可以。
写了一个示例程序来进行说明。下面是一些核心类的类图:
查看完整代码请移步 GitHub/zhyea
介绍下类图中类的作用:
如上面的解释中所说,在 MyJobFactory 的实现中, JobRegistry 是最重要的角色,在这个类中完成了 AbstractJob 实现类的实例的创建、维护和获取:
public class JobRegistry {
private final MyConfig config;
private final Map<Class<? extends AbstractJob>, AbstractJob> myJobMap;
public JobRegistry(MyConfig config) {
this.config = config;
myJobMap = myJobMap();
}
public AbstractJob getInstance(Class<? extends AbstractJob> clazz) {
return myJobMap.get(clazz);
}
public Iterable<AbstractJob> jobs() {
return myJobMap.values();
}
private Map<Class<? extends AbstractJob>, AbstractJob> myJobMap() {
Map<Class<? extends AbstractJob>, AbstractJob> m = new HashMap<>(2);
m.put(MyJob.class, new MyJob(config));
return m;
}
}
MyJobFactory 需要提供类的实例时,可以根据类名通过 JobRegistry . getInstance 获取到 AbstractJob 子类的实例:
if (AbstractJob.class.isAssignableFrom(jobClass)) {
return jobRegistry.getInstance((Class<? extends AbstractJob>) jobClass);
}
return jobClass.newInstance();
核心部分就是这样了。再看下AbstractJob及启动类的内容。
AbstractJob 近似于是是一个抽象模板类。在这个类里完成了JobDetail和Trigger实例的创建。当然Job接口的execute方法还是需要子类来实现。
public abstract class AbstractJob implements Job {
protected MyConfig config;
public AbstractJob(MyConfig config) {
this.config = config;
}
public abstract String identity();
public abstract int intervalSeconds();
public final JobDetail job() {
return newJob(this.getClass())
.withIdentity(identity())
.build();
}
public final Trigger trigger() {
return newTrigger()
.withIdentity(identity())
.startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(intervalSeconds()).repeatForever())
.build();
}
}
下面是启动类的内容,在这个类里通过 scheduler . setJobFactory 完成了 MyJobFactory 实例的装配:
public static void main(String[] args) throws SchedulerException {
MyConfig config = new MyConfig(1);
JobRegistry registry = new JobRegistry(config);
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.setJobFactory(new MyJobFactory(registry));
scheduler.start();
for(AbstractJob job : registry.jobs()){
scheduler.scheduleJob(job.job(), job.trigger());
}
}
就这样了。