iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >SpringBoot实现固定、动态定时任务 | 三种实现方式
  • 401
分享到

SpringBoot实现固定、动态定时任务 | 三种实现方式

springbootjavamybatis 2023-10-01 17:10:18 401人浏览 八月长安
摘要

前言: 阅读完本文:🐱‍👓 知晓 SpringBoot 用注解如何实现定时任务明白 springBoot 如何实现一个动态定时任务 (与数据库相关联实现)理解 SpringBoot 实现设置时间执行定时任务

前言:

阅读完本文:🐱‍👓

  1. 知晓 SpringBoot 用注解如何实现定时任务
  2. 明白 springBoot 如何实现一个动态定时任务 (与数据库相关联实现)
  3. 理解 SpringBoot 实现设置时间执行定时任务 (使用 ThreadPoolTaskScheduler 实现)

一、注解实现定时任务

用注解实现是真的简单,只要会 cron 表达式就行。🧙‍♂️

第一步: 主启动类上加上 @EnableScheduling 注解

@EnableScheduling@SpringBootApplicationpublic class SpringBootScheduled {    public static void main(String[] args) {        SpringApplication.run(SpringBootScheduled.class);    }}复制代码

第二步:写一个类,注入到Spring,关键就是 @Scheduled 注解。 () 里就是 cron 表达式,用来说明这个方法的执行周期的。 🛌

@Componentpublic class SchedulingTaskBasic {        @Scheduled(cron = "*/5 * * * * ?")    private void printNowDate() {        long nowDateTime = System.currentTimeMillis();        System.out.println("固定定时任务执行:--->"+nowDateTime+",此任务为每五秒执行一次");    }}复制代码

执行效果:

源码在文末。🏍

二、动态定时任务

其实也非常的简单。

2.1、建数据表

第一步:建个数据库表。

CREATE TABLE `tb_cron`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '动态定时任务时间表',  `cron_expression` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '定时任务表达式',  `cron_describe` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;INSERT INTO `tb_cron` VALUES (1, '0 0/1 * * * ?', '每分钟执行一次');复制代码

2.2、导入依赖,基础编码

第二步:导入数据库相关依赖,做到能从数据库查询数据。大家都会。🤸‍♂️

第三步: 编码

实体类:

@Data@TableName("tb_cron")public class Cron {    private Long id;    private String cronExpression;    private String cronDescribe;}复制代码

mapper层:

@Repositorypublic interface CronMapper extends BaseMapper {    @Select("select cron_expression from tb_cron where id=1")    String getCron1();}复制代码

2.3、主要实现代码

第四步:写一个类 实现 SchedulinGConfigurer🍻

实现 void configureTasks(ScheduledTaskReGIStrar taskRegistrar); 方法,此方法的作用就是根据给定的 ScheduledTaskRegistrar 注册 TaskScheduler 和特定的Task实例

@Componentpublic class CompleteScheduleConfig implements SchedulingConfigurer {    @Autowired    @SuppressWarnings("all")    CronMapper cronMapper;        @Override    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {        taskRegistrar.addTriggerTask(                //1.添加任务内容(Runnable)                () -> System.out.println("执行动态定时任务1: " + LocalDateTime.now().toLocalTime()+",此任务执行周期由数据库中的cron表达式决定"),                //2.设置执行周期(Trigger)                triggerContext -> {                    //2.1 从数据库获取执行周期                    String cron = cronMapper.getCron1();                    //2.2 合法性校验.                    if (cron!=null) {                        // Omitted Code ..                    }                    //2.3 返回执行周期(Date)                    return new CronTrigger(cron).nextExecutionTime(triggerContext);                }        );    }}复制代码

2.4、效果

注意:当你修改了任务执行周期后,生效时间为执行完最近一次任务后。这一点是需要注意的,用生活中的例子理解就是我们取消电话卡的套餐也要下个月生效,含义是一样的。

源码同样在文末。

三、实现设置时间定时任务

通常业务场景是我前言中说的那样,是一次性的定时任务。如:我设置了我写的这篇文章的发布时间为今天下午的两点,执行完就删除没有了。一次性的。

实现主要依靠于 TaskSchedulerScheduledFuture schedule(Runnable task, Trigger trigger);方法来实现。其本质和动态定时任务的实现是一样的。

3.1、实现重点

代码中都含有注解,不多做阐述。

import cn.hutool.core.convert.ConverterRegistry;import com.crush.scheduled.entity.Task;import lombok.extern.slf4j.Slf4j;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.util.*;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.CopyOnWriteArrayList;import java.util.concurrent.ScheduledFuture;@Component@Slf4jpublic class DynamicTaskService {        public Map> taskMap = new ConcurrentHashMap<>();    public List taskList = new CopyOnWriteArrayList();    private final ThreadPoolTaskScheduler syncScheduler;    public DynamicTaskService(ThreadPoolTaskScheduler syncScheduler) {        this.syncScheduler = syncScheduler;    }        public List getTaskList() {        return taskList;    }        public boolean add(Task task) {        // 此处的逻辑是 ,如果当前已经有这个名字的任务存在,先删除之前的,再添加现在的。(即重复就覆盖)        if (null != taskMap.get(task.getName())) {            stop(task.getName());        }        // hutool 工具包下的一个转换类型工具类 好用的很        ConverterRegistry converterRegistry = ConverterRegistry.getInstance();        Date startTime = converterRegistry.convert(Date.class, task.getStart());        // schedule :调度给定的Runnable ,在指定的执行时间调用它。        //一旦调度程序关闭或返回的ScheduledFuture被取消,执行将结束。        //参数:        //任务 – 触发器触发时执行的 Runnable        //startTime – 任务所需的执行时间(如果这是过去,则任务将立即执行,即尽快执行)        ScheduledFuture schedule = syncScheduler.schedule(getRunnable(task), startTime);        taskMap.put(task.getName(), schedule);        taskList.add(task.getName());        return true;    }        public Runnable getRunnable(Task task) {        return () -> {            log.info("---动态定时任务运行---");            try {                System.out.println("此时时间==>" + LocalDateTime.now());                System.out.println("task中设定的时间==>" + task);                Thread.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();            }            log.info("---end--------");        };    }        public boolean stop(String name) {        if (null == taskMap.get(name)) {            return false;        }        ScheduledFuture scheduledFuture = taskMap.get(name);        scheduledFuture.cancel(true);        taskMap.remove(name);        taskList.remove(name);        return true;    }}复制代码

3.2、异步线程池的配置

@Configurationpublic class ThreadPoolTaskExecutorConfig {    @Bean    public ThreadPoolTaskScheduler syncScheduler() {        ThreadPoolTaskScheduler syncScheduler = new ThreadPoolTaskScheduler();        syncScheduler.setPoolSize(5);        // 这里给线程设置名字,主要是为了在项目能够更快速的定位错误。        syncScheduler.setThreadGroupName("syncTg");        syncScheduler.setThreadNamePrefix("syncThread-");        syncScheduler.initialize();        return syncScheduler;    }}复制代码

3.3、业务代码

这里需要注意一个点,我给项目中的 LocalDateTime 做了类型转换。这里没贴出来(主要是复制以前的代码遗留下来的,源码中都有)

大家简单使用,可以直接用注解 标注在 LocalDateTime 属性上即可。

package com.crush.scheduled.controller;import com.crush.scheduled.entity.Task;import com.crush.scheduled.service.DynamicTaskService;import org.springframework.WEB.bind.annotation.*;import java.util.List;@RestController@RequestMapping("/dynamicTask")public class DynamicTaskController {    private final DynamicTaskService dynamicTask;    public DynamicTaskController(DynamicTaskService dynamicTask) {        this.dynamicTask = dynamicTask;    }        @GetMapping    public List getStartingDynamicTask(){        return dynamicTask.getTaskList();    }        @PostMapping("/dynamic")    public String startDynamicTask(@RequestBody Task task){        // 将这个添加到动态定时任务中去        dynamicTask.add(task);         return "动态任务:"+task.getName()+" 已开启";    }        @DeleteMapping("/{name}")    public String stopDynamicTask(@PathVariable("name") String name){        // 将这个添加到动态定时任务中去        if(!dynamicTask.stop(name)){            return "停止失败,任务已在进行中.";        }        return "任务已停止";    }}复制代码

简单封装的一个实体类:

@Data@Accessors(chain = true) // 方便链式编写 习惯所然 public class Task {        private String name;        private LocalDateTime start;}复制代码

3.4、效果

💫💨

开启一个动态任务:

查看开启还未执行的动态任务:

执行结果:

和我们代码中是一模一样的。

停止任务:

再去查看就是已经停止的拉

来源地址:https://blog.csdn.net/2301_76607156/article/details/129796248

--结束END--

本文标题: SpringBoot实现固定、动态定时任务 | 三种实现方式

本文链接: https://www.lsjlt.com/news/422336.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作