SpringBoot定时任务动态扩展ScheduledTaskRegistrar详解
摘要
本文主要介绍基于SpringBoot
定时任务ScheduledTaskRegistrar
的动态扩展,实现定时任务的动态新增和删除。
ScheduledTaskRegistrar类简要描述
平常使用方式配置
Application
启动类上添加注解@EnableScheduling
@EnableScheduling @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 在需要定时的方法上添加定时注解
@Scheduled(cron = "0/10 * * * * ?")
@Slf4j @Component public class OtherScheduler { @Scheduled(cron = "0/10 * * * * ?") public void print(){ log.info("每10S打印一次"); } @Scheduled(cron = "0/5 * * * * ?") public void print5(){ log.info("每5S打印一次"); } }
原理分析
默认的方式启动把ScheduledAnnotationBeanPostProcessor
该类实例化到SpringBoot
的Bean
管理中,并且该类持有一个ScheduledTaskRegistrar
属性,然后扫描出来拥有@Scheduled
注解的方法,添加到定时任务中。
- 添加定时任务到列表中
扫描到@Scheduled
注解的时候调用了该方法添加任务
public void addCronTask(Runnable task, String expression) { if (!CRON_DISABLED.equals(expression)) { addCronTask(new CronTask(task, expression)); } }
- 启动定时任务
在对象实例化完成后,调用了afterPropertiesSet
方法,该方法实际使用中执行了
public void afterPropertiesSet() { scheduleTasks(); } protected void scheduleTasks() { if (this.taskScheduler == null) { this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); } if (this.triggerTasks != null) { for (TriggerTask task : this.triggerTasks) { addScheduledTask(scheduleTriggerTask(task)); } } if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { addScheduledTask(scheduleCronTask(task)); } } if (this.fixedRateTasks != null) { for (IntervalTask task : this.fixedRateTasks) { addScheduledTask(scheduleFixedRateTask(task)); } } if (this.fixedDelayTasks != null) { for (IntervalTask task : this.fixedDelayTasks) { addScheduledTask(scheduleFixedDelayTask(task)); } } } private void addScheduledTask(@Nullable ScheduledTask task) { if (task != null) { this.scheduledTasks.add(task); } } // 启动任务核心方法 public ScheduledTask scheduleCronTask(CronTask task) { ScheduledTask scheduledTask = this.unresolvedTasks.remove(task); boolean newTask = false; if (scheduledTask == null) { scheduledTask = new ScheduledTask(task); newTask = true; } if (this.taskScheduler != null) { scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger()); } else { addCronTask(task); this.unresolvedTasks.put(task, scheduledTask); } return (newTask ? scheduledTask : null); }
DynamicScheduledTaskRegistrar 动态任务注册类
下面改动主要涉及到线程池数量、新增任务、删除任务、销毁任务四个方面;
public class DynamicScheduledTaskRegistrar extends ScheduledTaskRegistrar { private static final Logger log = LoggerFactory.getLogger(DynamicScheduledTaskRegistrar.class); private final Map<String,ScheduledTask> scheduledTaskMap = new LinkedHashMap<>(16); public DynamicScheduledTaskRegistrar(){ super(); // 两种实现方案 //ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); //TaskScheduler taskScheduler = new ConcurrentTaskScheduler(scheduledExecutorService); // 第二种实现方案 ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(8); taskScheduler.setRemoveOnCancelPolicy(true); taskScheduler.setThreadNamePrefix("dynamic-scheduled-task-"); taskScheduler.initialize(); this.setScheduler(taskScheduler); } /** * 新增任务 * @param taskName * @param cron * @param runnable */ public Boolean addCronTask(String taskName,String cron,Runnable runnable){ if(scheduledTaskMap.containsKey(taskName)){ log.error("定时任务["+ taskName+"]已存在,添加失败"); return Boolean.FALSE; } CronTask cronTask = new CronTask(runnable,cron); ScheduledTask scheduledTask = this.scheduleCronTask(cronTask); scheduledTaskMap.put(taskName,scheduledTask); log.info("定时任务["+taskName+"]新增成功"); return Boolean.TRUE; } /** * 删除任务 * @param taskName */ public void cancelCronTask(String taskName){ ScheduledTask scheduledTask = scheduledTaskMap.get(taskName); if(null != scheduledTask){ scheduledTask.cancel(); scheduledTaskMap.remove(taskName); } log.info("定时任务["+taskName+"]删除成功"); } @Override public void destroy() { super.destroy(); scheduledTaskMap.values().forEach(ScheduledTask::cancel); } }
线程池数量问题
由于默认是单线程的,如果任务阻塞时间过长则会导致后续的任务阻塞,所以尽量是异步任务或者是线程池数量大一点,则可以避免这个问题
DynamicScheduledTaskService
@Service public class DynamicScheduledTaskService { private static final Logger log = LoggerFactory.getLogger(DynamicScheduledTaskService.class); private final DynamicScheduledTaskRegistrar dynamicScheduledTaskRegistrar = new DynamicScheduledTaskRegistrar(); /** * 新增任务 * @param taskName * @param cron */ public void add(String taskName,String cron){ Boolean result = dynamicScheduledTaskRegistrar.addCronTask(taskName,cron,() -> print(taskName)); log.info("定时任务添加结果:" + result); } /** * 取消任务 * @param taskName */ public void cancel(String taskName){ dynamicScheduledTaskRegistrar.cancelCronTask(taskName); } private void print(String taskName){ log.info(taskName+"开始"); try{ Thread.sleep(9000L); log.info(taskName+"结束111"); }catch (Exception ex){ } log.info(taskName+"结束"); } }
SchedulerController
@RestController @RequestMapping(value = "scheduler") public class SchedulerController { @Autowired private DynamicScheduledTaskService dynamicScheduledTaskService; @GetMapping(value = "add") public Object add(String taskName,String cron){ dynamicScheduledTaskService.add(taskName,cron); return "SUCCESS"; } @GetMapping(value = "cancel") public Object cancel(String jobName){ dynamicScheduledTaskService.cancel(jobName); return "SUCCESS"; } }
测试结果
新增的任务都睡眠了9S
新增调度任务
删除调度任务
以上就是SpringBoot定时任务动态扩展ScheduledTaskRegistrar详解的详细内容,更多关于SpringBoot ScheduledTaskRegistrar的资料请关注脚本之家其它相关文章!
- SpringTask实现定时任务方法讲解
- SpringBoot ScheduledTaskRegistrar解决动态定时任务思路详解
- Spring动态管理定时任务之ThreadPoolTaskScheduler解读
- 使用spring-task定时任务动态配置修改执行时间
- Spring Task定时任务每天零点执行一次的操作
- SpringBoot2 task scheduler 定时任务调度器四种方式
- spring boot task实现动态创建定时任务的方法
- java 中Spring task定时任务的深入理解
- Spring Task定时任务的配置和使用详解
- SpringTask-Timer实现定时任务的详细代码
相关文章
SpringDataElasticsearch与SpEL表达式实现ES动态索引
这篇文章主要介绍了SpringDataElasticsearch与SpEL表达式实现ES动态索引,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下2022-09-09JDK安装与配置超级详细教程(包含二个或多个JDK的同时安装)
这篇文章主要给大家介绍了关于JDK安装与配置(包含二个或多个JDK的同时安装)的相关资料,对于Java学习者来说,一台电脑拿到手肯定要配置JDK,但是对于新手来说还是容易出错,需要的朋友可以参考下2023-10-10Hadoop 使用IntelliJ IDEA 进行远程调试代码的配置方法
这篇文章主要介绍了Hadoop 使用IntelliJ IDEA 进行远程调试代码的配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-04-04Hibernate环境搭建与配置方法(Hello world配置文件版)
这篇文章主要介绍了Hibernate环境搭建与配置方法,这里演示Hello world配置文件版的具体实现步骤与相关代码,需要的朋友可以参考下2016-03-03spring boot 项目利用Jenkins实现自动化部署的教程详解
这篇文章主要介绍了spring boot 项目利用Jenkins实现自动化部署的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下2018-07-07
最新评论