简单粗暴,玩转 SpringBoot 动态定时任务(启动、暂停)

您所在的位置:网站首页 配置定时任务时间 简单粗暴,玩转 SpringBoot 动态定时任务(启动、暂停)

简单粗暴,玩转 SpringBoot 动态定时任务(启动、暂停)

2024-07-03 18:46| 来源: 网络整理| 查看: 265

1a7568e9b91135d963bfc1e96617b661.jpeg

程序员的成长之路

互联网/程序员/技术/资料共享 

关注

阅读本文大概需要 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表达式来调度任务的执行。

5b127b04bf80a56fe379c7b8a541c4e1.png

在我的项目中主要用到了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