简单粗暴,玩转 SpringBoot 动态定时任务(启动、暂停) |
您所在的位置:网站首页 › 配置定时任务时间 › 简单粗暴,玩转 SpringBoot 动态定时任务(启动、暂停) |
程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 3.5 分钟。 来自:网络 最近在做一个项目,需要用到动态定时任务,现在比较普遍的做法是集成第三方框架(例如Quartz、XXL-JOB),我自己在做这个项目的时候也考虑过去集成Quartz实现,但是基于项目本身的复杂度和使用场景放弃了 本文主要分享在不依赖过多的其他框架,使用springBoot自身带有的定时任务框架来实现动态定时任务 注解实现定时任务具体实现主要基于@EnableScheduling和 @Scheduled注解主启动类上加上 @EnableScheduling 注解 写一个类,注入到容器中,在方法上加上 @Scheduled 注解 @Slf4j @Component public class TimeTask { @Scheduled(cron = "0 0/31 * * * ?") public void refresh(){ log.info(" 定时刷新"); //业务代码 } }这样就实现了定时任务,是不是很简单?不难发现,这种方式定时执行时间是固定的,但是大部分业务的定时执行时间是经常在变化的,这时候我们就需要通过动态定时任务实现 实现动态定时任务Spring实现动态定时任务的核心就是其提供的任务调度类ThreadPoolTaskScheduler,ThreadPoolTaskScheduler基于线程池来执行任务,可以按照固定的时间间隔或者指定的Cron表达式来调度任务的执行。 在我的项目中主要用到了ScheduledFuture schedule(Runnable task, Trigger trigger)方法,指定的Cron表达式来调度任务的执行 具体实现创建ThreadPoolTaskScheduler配置类 @Configuration public class SchedulingConfig { @Bean public TaskScheduler taskScheduler() { // 获取系统处理器个数, 作为线程池数量 int corePoolSize = Runtime.getRuntime().availableProcessors(); ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); // 定时任务执行线程池核心线程数 taskScheduler.setPoolSize(corePoolSize); taskScheduler.setRemoveOnCancelPolicy(true); taskScheduler.setThreadNamePrefix("AntiFraudSchedulerThreadPool-"); return taskScheduler; } }创建ScheduledTask包装类 ScheduledFuture是ScheduledFuture schedule(Runnable task, Trigger trigger)方法的返回值。 ScheduledFuture继承了Future接口,Future接口提供一组辅助方法,比如: cancel():取消任务 isCancelled():任务是不是取消了 isDone():任务是不是已经完成了 get():用来获取执行结果 当我们调用cancel方法时,会将我们的任务从workQueue中移除 public final class ScheduledTask { public volatile ScheduledFuture future; /** * 取消定时任务 */ public void cancel() { ScheduledFuture scheduledFuture = this.future; if (Objects.nonNull(scheduledFuture)) { scheduledFuture.cancel(true); } } }创建CronTaskRegistrar类 实现了DisposableBean接口的类,用于注册定时任务。它具有添加、删除和调度定时任务的方法。在销毁时,会取消所有定时任务。 @Slf4j @Component @SuppressWarnings("all") public class CronTaskRegistrar implements DisposableBean { @Resource private TaskScheduler taskScheduler; // 保存任务Id和定时任务 private final Map scheduledTaskMap = new ConcurrentHashMap(64); // 添加任务 public void addTask(Runnable task, String cronExpression,String jobId) { addTask(new CronTask(task, cronExpression),jobId); } public void addTask(CronTask cronTask,String jobId) { if (Objects.nonNull(cronTask)) { Runnable task = cronTask.getRunnable(); if (this.scheduledTasks.containsKey(task)) { removeTask(jobId); } // 保存任务Id和定时任务 this.scheduledTaskMap.put(jobId, scheduleTask(cronTask)); } } // 通过任务Id,取消定时任务 public void removeTask(String jobId) { ScheduledTask scheduledTask = this.scheduledTaskMap.remove(jobId); if (Objects.nonNull(scheduledTask)) { scheduledTask.cancel(); } } public ScheduledTask scheduleTask(CronTask cronTask) { ScheduledTask scheduledTask = new ScheduledTask(); scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger()); return scheduledTask; } // 销毁 @Override public void destroy() { this.scheduledTaskMap.values().forEach(ScheduledTask::cancel); this.scheduledTaskMap.clear(); } }动态定时任务的核心逻辑到这基本就已经完成了,具体的Service类代码,这里就不贴出来了,因为里面基本上都是业务逻辑和CronTaskRegistrar类的编排(ps:需要的也可以私聊demo) 定时任务表设计 create table schedule_setting ( id varchar(32) not null comment '唯一id' primary key, job_id varchar(64) null comment '任务ID', cron_expression varchar(255) null comment 'cron表达式', job_result varchar(32) null comment '任务结果(通过 复议 拒绝)', create_date datetime null comment '创建时间', status varchar(4) null, create_by varchar(64) null comment '创建人账号', creator varchar(64) null comment '创建人', version bigint(19) null comment '版本号' ) comment '定时任务表';项目启动时加载所有任务 @Component @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ScheduleRunner implements CommandLineRunner { ScheduleSettingRepository scheduleSettingRepository; CronTaskRegistrar scheduledTaskRegistrar; @Override public void run(String... args) throws Exception { // 查询所有定时任务 List scheduleSettingList=scheduleSettingRepository.findByStatus(EnableFlag.Y.name()); for (ScheduleSetting scheduleSetting : scheduleSettingList) { //调用CronTaskRegistrar添加任务方法 scheduledTaskRegistrar.addCronTask(() -> { ··· 任务执行方法 ... }, scheduleSetting.getCronExpression(), scheduleSetting.getJobId()); } } }至此,动态定时任务就说完啦。 推荐阅读: 网易二面:CPU狂飙900%,该怎么处理? 全新的分布式锁,几行代码搞定,简单且强大 互联网初中高级大厂面试题(9个G) 内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈! ⬇戳阅读原文领取! 朕已阅 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |