转载

Quartz Job类使用有参数构造方法

也许这篇文章的名字应该改成《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;
        }
    }

相当简单的内容,只需要在创建实例那块儿填写自定义的内容就可以。

写了一个示例程序来进行说明。下面是一些核心类的类图:

Quartz Job类使用有参数构造方法

查看完整代码请移步 GitHub/zhyea

介绍下类图中类的作用:

  • AbstractJob :抽象类,实现了Job接口,并提供了部分自定义方法,以及一个MyConfig参数的构造器
  • MyConfig :全局配置类,提供配置信息
  • JobRegistry :负责创建并维护AbstractJob实例
  • MyJobFactory :自定义的JobFactory实现类
  • MyJob :AbstractJob的一个子类,实现了Job的execute()方法

如上面的解释中所说,在 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());
        }
    }

就这样了。

原文  https://www.zhyea.com/2019/07/06/quartz-job-constructor-with-args.html
正文到此结束
Loading...