如何在Spring中使用EnableScheduling注释在运行时重新启动计划任务?

我一直在研究如何使用Java 8和spring更改运行时作业的频率。 这个问题非常有用,但并没有完全解决我的问题。

我现在可以配置下一次应该执行作业的日期。 但是如果将延迟设置为1年,那么我需要在考虑新配置之前等待1年。

我的想法是在配置值发生变化时停止计划任务(所以从另一个类开始)。 然后在下次执行任务时重新计算。 也许有一种更简单的方法可以做到这一点。

这是我到目前为止的代码。

@Configuration @EnableScheduling public class RequestSchedulerConfig implements SchedulingConfigurer { @Autowired SchedulerConfigService schedulerConfigService; @Bean public RequestScheduler myBean() { return new RequestScheduler(); } @Bean(destroyMethod = "shutdown") public Executor taskExecutor() { return Executors.newScheduledThreadPool(100); } @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(taskExecutor()); taskRegistrar.addTriggerTask( new Runnable() { @Override public void run() { myBean().startReplenishmentComputation(); } }, new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) { Duration d = schedulerConfigService.getIntervalFromDB(); return DateTime.now().plus(d).toDate(); } } ); } } 

这就是我想做的事情。

 @RestController @RequestMapping("/api/config/scheduler") public class RequestSchedulerController { @Autowired ApplicationConfigWrapper applicationConfigWrapper; @RequestMapping("/set/") @ResponseBody public String setRequestSchedulerConfig(@RequestParam(value = "frequency", defaultValue = "") final String frequencyInSeconds){ changeValueInDb(frequencyInSeconds); myJob.restart(); return "Yeah"; } } 

  1. 创建一个获取注入的TaskScheduler的单例bean。 这将作为状态变量保存所有ScheduledFuture ,如private ScheduledFuture job1;
  2. 在部署时,从数据库加载所有计划数据并启动作业,填写所有状态变量,如job1
  3. 在更改调度数据时, 取消相应的Future (例如job1 ),然后使用新的调度数据再次启动它。

这里的关键思想是在创建Future控制它们,以便将它们保存在某些状态变量中,这样当调度数据中的某些内容发生变化时,您可以取消它们。

这是工作代码:

applicationContext.xml中

   

持有Future s的单例bean

 @Component public class SchedulerServiceImpl implements SchedulerService { private static final Logger logger = LoggerFactory.getLogger(SchedulerServiceImpl.class); @Autowired @Qualifier(value="infScheduler") private TaskScheduler taskScheduler; @Autowired private MyService myService; private ScheduledFuture job1;//for other jobs you can add new private state variables //Call this on deployment from the ScheduleDataRepository and everytime when schedule data changes. @Override public synchronized void scheduleJob(int jobNr, long newRate) {//you are free to change/add new scheduling data, but suppose for now you only want to change the rate if (jobNr == 1) {//instead of if/else you could use a map with all job data if (job1 != null) {//job was already scheduled, we have to cancel it job1.cancel(true); } //reschedule the same method with a new rate job1 = taskScheduler.scheduleAtFixedRate(new ScheduledMethodRunnable(myService, "methodInMyServiceToReschedule"), newRate); } } } 

一种简单的方法是只添加新任务,而不是尝试取消或重新启动调度程序。

每次配置更改时,只需使用新配置添加新任务。

然后,每当任务运行时,它必须首先检查某个状态(通过查询数据库,或在并发映射中查找,或其他任何)来确定它是否是最新版本。 如果是,那么它应该继续。 否则,它应该立即结束。

唯一的缺点是,如果您经常更改作业配置与其运行频率相比,那么当然,计划任务列表将在内存中不断增长。