使用石英调度程序在弹簧启动中进行动态作业调度

时间:2019-03-25 18:20:49

标签: java spring spring-boot quartz-scheduler

我想根据用户从UI提供的计划配置动态地计划作业。每当用户从UI保存新的计划配置时,该过程就必须使用新的计划参数来调用新作业。可以有n种配置来执行同一作业。 Spring支持作业详细信息和触发器的实现,如下所示。

定义作业详细信息:

@Bean
public JobDetail jobDetail() {
    return JobBuilder.newJob().ofType(SampleJob.class)
      .storeDurably()
      .withIdentity("Qrtz_Job_Detail")  
      .withDescription("Invoke Sample Job service...")
      .build();
}

定义触发器:

@Bean
public Trigger trigger(JobDetail job) {
    return TriggerBuilder.newTrigger().forJob(job)
      .withIdentity("Qrtz_Trigger")
      .withDescription("Sample trigger")
      .withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
      .build();
}

如何传递作业详细信息的参数并根据用户提供的参数动态触发?

2 个答案:

答案 0 :(得分:1)

最简单的方法是通过扩展SpringBeanJobFactory@Override createJobInstance 方法进行一些配置。然后,您需要定义SchedulerFactoryBean,最后定义Scheduler

@Configuration
public class SchedulerConfiguration {

    public class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {

        private final AutowireCapableBeanFactory beanFactory;

        @Autowired
        public AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
            Assert.notNull(beanFactory, "Bean factory must not be null");
            this.beanFactory = beanFactory;
        }

        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            Object jobInstance = super.createJobInstance(bundle);
            this.beanFactory.autowireBean(jobInstance);
            this.beanFactory.initializeBean(jobInstance, null);
            return jobInstance;
        }
    }

    @Bean
    public SchedulerFactoryBean schedulerFactory(ApplicationContext applicationContext) {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory(applicationContext.getAutowireCapableBeanFactory()));
        return schedulerFactoryBean;
    }

    @Bean
    public Scheduler scheduler(ApplicationContext applicationContext) throws SchedulerException {
        Scheduler scheduler = schedulerFactory(applicationContext).getScheduler();
        scheduler.start();
        return scheduler;
    }
}

然后在应用程序中的任何位置(例如在RestController中),您都可以访问调度程序并调度新作业:

@RestController
public class ScheduleController {

    @Autowired
    private Scheduler scheduler;

    @GetMapping(value = "/schedule/{detail}/{desc}")
    public String scheduleJob(@PathVariable(value = "detail") String detail, @PathVariable(value = "desc") String desc) throws SchedulerException {
        JobDetail job = newJob(detail, desc);
        return scheduler.scheduleJob(job, trigger(job)).toString();
    }

    private JobDetail newJob(String identity, String description) {
        return JobBuilder.newJob().ofType(SimpleJob.class).storeDurably()
                .withIdentity(JobKey.jobKey(identity))
                .withDescription(description)
                .build();
    }

    private SimpleTrigger trigger(JobDetail jobDetail) {
        return TriggerBuilder.newTrigger().forJob(jobDetail)
                .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
                .build();
    }
}

您可以通过Scheduler-look at the documentation

控制所有时间表(暂停,停止,重启,删除等)。

答案 1 :(得分:0)

这是JobDataMap参数的作用。您可以使用这些参数将任意参数传递给作业和触发器。通常建议使用String参数值以避免各种序列化问题。 JobDataMap API提供了辅助方法,可用于将字符串值的JobDataMap参数值转换为各种基本Java对象(整数,长整数,双精度,布尔型等)。

请注意,在JobDetail级别上指定的JobDataMap参数可以在Trigger级别上被覆盖。在JobDetail级别上,通常指定所有作业执行应使用的通用参数和/或默认值,并覆盖这些默认值和/或在Trigger级别上添加新参数。

有关详细信息,请参考Quartz Javadoc:

JobBuilder.html#usingJobData

TriggerBuilder.html#usingJobData

JobDataMap.html