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

这篇具有很好参考价值的文章主要介绍了SpringBoot实现固定、动态定时任务 | 三种实现方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

阅读完本文:🐱‍👓

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

一、注解实现定时任务

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

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

@EnableScheduling
@SpringBootApplication
public class SpringBootScheduled {

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

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

/**
 * 定时任务 静态定时任务
 *
 * 第一位,表示秒,取值0-59
 * 第二位,表示分,取值0-59
 * 第三位,表示小时,取值0-23
 * 第四位,日期天/日,取值1-31
 * 第五位,日期月份,取值1-12
 * 第六位,星期,取值1-7,1表示星期天,2表示星期一
 * 第七位,年份,可以留空,取值1970-2099
 * @author crush
 * @since 1.0.0
 * @Date: 2021-07-27 21:13
 */
@Component
public class SchedulingTaskBasic {

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

执行效果:

spring定时任务动态配置,spring boot,java,mybatis

源码在文末。🏍

二、动态定时任务

其实也非常的简单。

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层:

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

2.3、主要实现代码

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

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

@Component
public 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、效果

spring定时任务动态配置,spring boot,java,mybatis

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

源码同样在文末。

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

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

实现主要依靠于 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;

/**
 * @author crush
 */
@Component
@Slf4j
public class DynamicTaskService {

    /**
     * 以下两个都是线程安全的集合类。
     */
    public Map<String, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
    public List<String> taskList = new CopyOnWriteArrayList<String>();


    private final ThreadPoolTaskScheduler syncScheduler;

    public DynamicTaskService(ThreadPoolTaskScheduler syncScheduler) {
        this.syncScheduler = syncScheduler;
    }

    /**
     * 查看已开启但还未执行的动态任务
     * @return
     */
    public List<String> getTaskList() {
        return taskList;
    }


    /**
     * 添加一个动态任务
     *
     * @param task
     * @return
     */
    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;
    }


    /**
     * 运行任务
     *
     * @param task
     * @return
     */
    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--------");
        };
    }

    /**
     * 停止任务
     *
     * @param name
     * @return
     */
    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、异步线程池的配置

/**
 * 异步线程池ThreadPoolExecutor 配置类
 *
 * @Author: crush
 * @Date: 2021-07-23 14:14
 */
@Configuration
public 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;

/**
 * @Author: crush
 * @Date: 2021-07-29 15:26
 * version 1.0
 */
@RestController
@RequestMapping("/dynamicTask")
public class DynamicTaskController {

    private final DynamicTaskService dynamicTask;

    public DynamicTaskController(DynamicTaskService dynamicTask) {
        this.dynamicTask = dynamicTask;
    }

    /**
     * 查看已开启但还未执行的动态任务
     * @return
     */
    @GetMapping
    public List<String> getStartingDynamicTask(){
        return dynamicTask.getTaskList();
    }


    /**
     * 开启一个动态任务
     * @param task
     * @return
     */
    @PostMapping("/dynamic")
    public String startDynamicTask(@RequestBody Task task){
        // 将这个添加到动态定时任务中去
        dynamicTask.add(task);
         return "动态任务:"+task.getName()+" 已开启";
    }


    /**
     *  根据名称 停止一个动态任务
     * @param name
     * @return
     */
    @DeleteMapping("/{name}")
    public String stopDynamicTask(@PathVariable("name") String name){
        // 将这个添加到动态定时任务中去
        if(!dynamicTask.stop(name)){
            return "停止失败,任务已在进行中.";
        }
        return "任务已停止";
    }

}
复制代码

简单封装的一个实体类:

/**
 * @Author: crush
 * @Date: 2021-07-29 15:35
 * version 1.0
 */
@Data
@Accessors(chain = true) // 方便链式编写 习惯所然 
public class Task {
    /**
     * 动态任务名曾
     */
    private String name;

    /**
     * 设定动态任务开始时间
     */
    private LocalDateTime start;
}
复制代码

3.4、效果

💫💨

开启一个动态任务:

spring定时任务动态配置,spring boot,java,mybatis

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

spring定时任务动态配置,spring boot,java,mybatis

执行结果:

spring定时任务动态配置,spring boot,java,mybatis

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

spring定时任务动态配置,spring boot,java,mybatis

停止任务:

spring定时任务动态配置,spring boot,java,mybatis

spring定时任务动态配置,spring boot,java,mybatis

再去查看就是已经停止的拉文章来源地址https://www.toymoban.com/news/detail-598939.html

到了这里,关于SpringBoot实现固定、动态定时任务 | 三种实现方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot开启动态定时任务并手动、自动关闭

    场景需求:在执行某个方法的两小时之后进行某个操作 涉及:定时任务、哈希表 需要注意: 业务逻辑层是单一实例的,所以在定时任务类内操作业务逻辑层的某个属性和在业务逻辑层内操作的都是同一个。 使用Map存放数据不要用IdentityHashMap,因为IdentityHashMap比较key值用的是

    2024年01月24日
    浏览(47)
  • SpringBoot 中实现定时任务的几种方式

    定时任务在我们项目开发中也是很重要的,对于某些场景必须要用定时任务 ,如定时发送邮件啊,定时统计数据等,这篇文章主要讲讲项目中实现定时任务的几种方式。 这种方式很简单,主要就是先@EnableScheduling开启定时任务功能,然后在相应的方法上添加@Scheduled()中间写上

    2024年02月03日
    浏览(48)
  • SpringBoot第47讲:SpringBoot定时任务 - Netty HashedWheelTimer方式

    timer 和 ScheduledExecutorService 是JDK内置的定时任务方案,而业内还有一个经典的定时任务的设计叫时间轮(Timing Wheel), Netty 内部基于时间轮实现了一个 HashedWheelTimer 来 优化百万量级I/O超时的检测 ,它是一个高性能,低消耗的数据结构,它适用于非准实时,延迟的短平快任务,例

    2024年02月09日
    浏览(39)
  • SpringBoot 动态操作定时任务(启动、停止、修改执行周期)增强版

    前段时间编写了一篇博客 SpringBoot 动态操作定时任务(启动、停止、修改执行周期 ,该篇博客还是帮助了很多同学。 但是该篇博客中的方法有些不足的地方: 只能通过前端控制器controller手动注册任务。【具体的应该是我们提前配置好我们的任务,配置完成后让springboot应用

    2024年02月13日
    浏览(39)
  • Java -- 定时任务实现方式

    在Java开发中,定时任务是一种十分常见的功能. 定时任务是在约定时间内执行的一段程序 如每天凌晨24点备份同步数据,又或者电商平台 30 分钟后自动取消未支付的订单,每隔一个小时拉取一次数据等都需要使用到定时器 批量处理数据:批量统计上个月的某个数据。 时间驱

    2024年02月02日
    浏览(37)
  • Quartz实战:基于Quartz实现定时任务的动态调度,实现定时任务的增删改查

    Quartz使用文档,使用Quartz实现动态任务,Spring集成Quartz,Quartz集群部署,Quartz源码分析 Quartz使用文档,使用Quartz实现动态任务,Spring集成Quartz,Quartz集群部署,Quartz源码分析 此处省略了SysJob实体类,以及Mapper等对数据库的操作。 本文只是大致实现一个基于Quartz实现定时任务

    2024年02月15日
    浏览(47)
  • springboot---定时任务实现

    任意类中创建一个方法,将该方法用@scheduled注解修饰,然后在项目的主方法上添加@EnableScheduling注解,定时任务就会生效。 但是需要注意的是定时任务不会一开始就执行,会等待设定的时间 1.2.1. cron cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个域,每一个

    2024年02月11日
    浏览(38)
  • SpringBoot 实现定时任务

    定时任务在实际项目开发中很常见,并且定时任务可以在各种场景中应用,通过自动化操作和任务的规模化管理,提高效率、可靠性和工作质量。可以减少手动操作,避免疏忽和错误,并节省时间和人力资源的投入 简单易用: 使用注解驱动的方式,简化了定时任务的配置和

    2024年02月12日
    浏览(56)
  • python实现定时任务的8种方式详解

            在日常工作中,常常会用到需要周期性执行的任务,一种方式是采用 Linux 系统自带的 crond 结合命令行实现。另外一种方式是直接使用Python。                 当每隔一段时间就要执行一段程序,或者往复循环执行某一个任务,这就需要使用定时任务来执行

    2023年04月09日
    浏览(30)
  • linux下实现定时器的三种简单方式

    目录 一. sleep()和usleep() 1.sleep() 2.usleep() 3.毫秒级延时 二. signal与alarm() 三. select 四. 一些总结         优点是简单便捷,直接调用即可,但是缺点也很明显,精度不够,特别是在系统负载比较大时,会发生超时现象。 1.sleep() #include unistd.h unsigned int sleep(unsigned int   secon

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包