也许这篇文章的名字应该改成《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
的一些代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
介绍下类图中类的作用:
AbstractJob
:抽象类,实现了Job接口,并提供了部分自定义方法,以及一个MyConfig参数的构造器MyConfig
:全局配置类,提供配置信息JobRegistry
:负责创建并维护AbstractJob实例MyJobFactory
:自定义的JobFactory实现类MyJob
:AbstractJob的一个子类,实现了Job的execute()方法
如上面的解释中所说,在MyJobFactory
的实现中,JobRegistry
是最重要的角色,在这个类中完成了AbstractJob
实现类的实例的创建、维护和获取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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
子类的实例:
1 2 3 4 5 |
if (AbstractJob.class.isAssignableFrom(jobClass)) { return jobRegistry.getInstance((Class<? extends AbstractJob>) jobClass); } return jobClass.newInstance(); |
核心部分就是这样了。再看下AbstractJob及启动类的内容。
AbstractJob
近似于是是一个抽象模板类。在这个类里完成了JobDetail和Trigger实例的创建。当然Job接口的execute方法还是需要子类来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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
实例的装配:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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()); } } |
就这样了。
发表评论