spring boot 学习笔记(4) 动态创建定时任务
2017-03-21 00:00
483 查看
摘要: 在spring boot中使用定时任务特别简单,只需要使用@EnableScheduling注解开启定时任务,然后在每个定时任务类方法上加上@Scheduled注解,就可以轻松的实现定时任务。
最近项目里面需要做动态定时任务的功能,需要查询数据库里面的某个表,然后动态的创建、修改、删除定时任务。作为一个伸手党,本来想着上网一查就能找到现成的方案,结果找了半天也没找到合适的,没办法自己动手研究一下吧。
还好在官方文档中翻到了一个SchedulingConfigurer类,查看源码发现configureTasks方法中,可以通过ScheduledTaskRegistrar.addCronTask实例来添加任务,嗯,看起来有戏,动手试一下。实现思路如下:
通过@Scheduled注解创建一个定时任务,30秒执行一次,用于加载数据库中的定时任务列表
继承SchedulingConfigurer类,通过ScheduledTaskRegistrar.addCronTask实例来添加任务
创建DynamicTaskRunable 用来执行对应的任务操作
当我几下把代码写出来之后,迫不及待的运行起来试了试,然而并没有什么用。。。
又看了一下源码才发现ScheduledTaskRegistrar.addCronTask只是把任务放到列表里面,只有在调用scheduleTasks方法的时候才会真正的创建定时任务,而这个方法只有在实例化之后才会去调用。于是脑袋上的小灯泡闪了一下,在refreshTasks方法中调用ScheduledTaskRegistrar.afterPropertiesSet()。于是我又迫不及待的试了试,诶,居然可以了。
毕竟我还是太年轻,正当我沾沾自喜的时候,发现定时任务的数量越来越多了,我勒个去,这不是我想要的。看样子一定是我打开的方式不对。继续看源码吧!
仔细查看源码发现ScheduledTaskRegistrar.scheduleTasks()方法每次都会遍历任务列表并且调用TaskScheduler.schedule()创建定时任务,所以才会创建很多的定时任务。
既然是通过TaskScheduler.schedule()创建定时任务的,那就在它上面想办法吧。改造之后的DynamicTaskConfigurer类如下:
再跑起来看了一下,暂时没有问题,后面再充分测试看看。。。
https://github.com/sergewu/spbd/tree/master/spbd-task
THE END
最近项目里面需要做动态定时任务的功能,需要查询数据库里面的某个表,然后动态的创建、修改、删除定时任务。作为一个伸手党,本来想着上网一查就能找到现成的方案,结果找了半天也没找到合适的,没办法自己动手研究一下吧。
还好在官方文档中翻到了一个SchedulingConfigurer类,查看源码发现configureTasks方法中,可以通过ScheduledTaskRegistrar.addCronTask实例来添加任务,嗯,看起来有戏,动手试一下。实现思路如下:
通过@Scheduled注解创建一个定时任务,30秒执行一次,用于加载数据库中的定时任务列表
继承SchedulingConfigurer类,通过ScheduledTaskRegistrar.addCronTask实例来添加任务
创建DynamicTaskRunable 用来执行对应的任务操作
package com.spbd.task.job; import java.util.List; import javax.annotation.PreDestroy; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.CronTask; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.stereotype.Component; import com.spbd.task.model.TimingTask; @Component public class DynamicTaskConfigurer implements SchedulingConfigurer { private volatile ScheduledTaskRegistrar registrar; @Override public void configureTasks(ScheduledTaskRegistrar registrar) { this.registrar = registrar; } public void refreshTasks(List<TimingTask> tasks){ for (TimingTask tt : tasks) { //判断是否已经存在该任务 if(hasTask(tt.getTaskId())){ DynamicTaskRunable t = new DynamicTaskRunable(tt.getTaskId()); String expression = tt.getExpression(); CronTask task = new CronTask(t, expression); registrar.addCronTask(task); } } } private boolean hasTask(Integer taskId){ List<CronTask> taskList = registrar.getCronTaskList(); for (CronTask cronTask : taskList) { if(cronTask.getRunnable() instanceof DynamicTaskRunable){ DynamicTaskRunable r = (DynamicTaskRunable) cronTask.getRunnable(); if(r.getTaskId().equals(taskId)){ return true; } } } return false; } @PreDestroy public void destroy() { this.registrar.destroy(); } }
package com.spbd.task.job; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import com.spbd.task.model.TimingTask; @Component public class DynamicTask { private final static Logger LOGGER =Logger.getLogger(DynamicTaskRunable.class); @Autowired private DynamicTaskConfigurer dynamicTaskConfigurer; @Scheduled(cron="0/30 * * * * ?") public void loadTasks(){ LOGGER.info("DynamicTask 正在执行......"); //从数据库查询 List<TimingTask> tasks = new ArrayList<TimingTask>(); dynamicTaskConfigurer.refreshTasks(tasks); } }
package com.spbd.task.job; import org.apache.log4j.Logger; public class DynamicTaskRunable implements Runnable{ private final static Logger LOGGER =Logger.getLogger(DynamicTaskRunable.class); private Integer taskId; public DynamicTaskRunable(Integer taskId) { this.taskId = taskId; } @Override public void run() { LOGGER.info("DynamicTaskRunable is running, taskId:"+taskId); } public Integer getT 7ff0 askId() { return taskId; } }
当我几下把代码写出来之后,迫不及待的运行起来试了试,然而并没有什么用。。。
又看了一下源码才发现ScheduledTaskRegistrar.addCronTask只是把任务放到列表里面,只有在调用scheduleTasks方法的时候才会真正的创建定时任务,而这个方法只有在实例化之后才会去调用。于是脑袋上的小灯泡闪了一下,在refreshTasks方法中调用ScheduledTaskRegistrar.afterPropertiesSet()。于是我又迫不及待的试了试,诶,居然可以了。
毕竟我还是太年轻,正当我沾沾自喜的时候,发现定时任务的数量越来越多了,我勒个去,这不是我想要的。看样子一定是我打开的方式不对。继续看源码吧!
仔细查看源码发现ScheduledTaskRegistrar.scheduleTasks()方法每次都会遍历任务列表并且调用TaskScheduler.schedule()创建定时任务,所以才会创建很多的定时任务。
既然是通过TaskScheduler.schedule()创建定时任务的,那就在它上面想办法吧。改造之后的DynamicTaskConfigurer类如下:
package com.spbd.task.job; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; import javax.annotation.PreDestroy; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.CronTask; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import com.spbd.task.model.TimingTask; @Component public class DynamicTaskConfigurer implements SchedulingConfigurer { private volatile ScheduledTaskRegistrar registrar; private final ConcurrentHashMap<Integer, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<Integer, ScheduledFuture<?>>(); private final ConcurrentHashMap<Integer, CronTask> cronTasks = new ConcurrentHashMap<Integer, CronTask>(); @Override public void configureTasks(ScheduledTaskRegistrar registrar) { this.registrar = registrar; } public void refreshTasks(List<TimingTask> tasks){ //取消已经删除的策略任务 Set<Integer> sids = scheduledFutures.keySet(); for (Integer sid : sids) { if(!exists(tasks, sid)){ scheduledFutures.get(sid).cancel(false); } } for (TimingTask tt : tasks) { DynamicTaskRunable t = new DynamicTaskRunable(tt.getTaskId()); String expression = tt.getExpression(); if(StringUtils.isEmpty(expression)){ continue; } if(scheduledFutures.containsKey(tt.getTaskId()) && cronTasks.get(tt.getTaskId()).getExpression().equals(expression)){ continue; } //如果策略执行时间发生了变化,则取消当前策略的任务 if(scheduledFutures.containsKey(tt.getTaskId())){ scheduledFutures.get(tt.getTaskId()).cancel(false); scheduledFutures.remove(tt.getTaskId()); cronTasks.remove(tt.getTaskId()); } CronTask task = new CronTask(t, expression); ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger()); cronTasks.put(tt.getTaskId(), task); scheduledFutures.put(tt.getTaskId(), future); } } private boolean exists(List<TimingTask> tasks,Integer tid){ for(TimingTask task:tasks){ if(task.getTaskId().equals(tid)){ return true; } } return false; } @PreDestroy public void destroy() { this.registrar.destroy(); } }
再跑起来看了一下,暂时没有问题,后面再充分测试看看。。。
https://github.com/sergewu/spbd/tree/master/spbd-task
THE END
相关文章推荐
- 反射学习笔记之动态创建对象和调用方法
- 动态链接库创建与使用(学习笔记) .
- java 定时任务(基于java学习笔记)
- 转:C++动态内存创建与内存管理学习笔记[1]
- PHP 开发 APP 接口学习笔记与总结 - [ Linux ] 定时任务
- C++动态内存创建与内存管理学习笔记[3]
- Quartz.net 2.x 学习笔记03-使用反射加载定时任务
- C++动态内存创建与内存管理学习笔记
- uC/OS-II 学习笔记:任务创建步骤
- C++动态内存创建与内存管理学习笔记【转】
- C++动态内存创建与内存管理学习笔记[1]
- Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度
- 转:C++动态内存创建与内存管理学习笔记[2]
- C++动态内存创建与内存管理学习笔记[2]
- SharePoint 2010学习笔记之一:创建”最新动态”WebPart
- Linux下学习crontab定时任务笔记
- iOS开发学习笔记 -- (三)动态创建视图
- Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度
- FreeRTOS学习笔记——创建任务
- 动态链接库创建与使用(学习笔记)