SpringBoot實現(xiàn)固定和動態(tài)定時任務(wù)的三種方法
前言:
閱讀完本文:
- 知曉
SpringBoot用注解如何實現(xiàn)定時任務(wù) - 明白
SpringBoot如何實現(xiàn)一個動態(tài)定時任務(wù) (與數(shù)據(jù)庫相關(guān)聯(lián)實現(xiàn)) - 理解
SpringBoot實現(xiàn)設(shè)置時間執(zhí)行定時任務(wù) (使用ThreadPoolTaskScheduler實現(xiàn))
一、注解實現(xiàn)定時任務(wù)
用注解實現(xiàn)是真的簡單,只要會 cron 表達式就行。
第一步: 主啟動類上加上 @EnableScheduling 注解
@EnableScheduling
@SpringBootApplication
public class SpringBootScheduled {
public static void main(String[] args) {
SpringApplication.run(SpringBootScheduled.class);
}
}第二步:寫一個類,注入到Spring,關(guān)鍵就是 @Scheduled 注解。 () 里就是 cron 表達式,用來說明這個方法的執(zhí)行周期的。
/**
* 定時任務(wù) 靜態(tài)定時任務(wù)
*
* 第一位,表示秒,取值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 {
/**
* 每五秒執(zhí)行一次
*/
@Scheduled(cron = "*/5 * * * * ?")
private void printNowDate() {
long nowDateTime = System.currentTimeMillis();
System.out.println("固定定時任務(wù)執(zhí)行:--->"+nowDateTime+",此任務(wù)為每五秒執(zhí)行一次");
}
}執(zhí)行效果:

二、動態(tài)定時任務(wù)
其實也非常的簡單。
2.1、建數(shù)據(jù)表
第一步:建個數(shù)據(jù)庫表。
CREATE TABLE `tb_cron` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '動態(tài)定時任務(wù)時間表', `cron_expression` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '定時任務(wù)表達式', `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 * * * ?', '每分鐘執(zhí)行一次');
2.2、導(dǎo)入依賴,基礎(chǔ)編碼
第二步:導(dǎo)入數(shù)據(jù)庫相關(guān)依賴,做到能從數(shù)據(jù)庫查詢數(shù)據(jù)。大家都會。??♂?
第三步: 編碼
實體類:
@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、主要實現(xiàn)代碼
第四步:寫一個類 實現(xiàn) SchedulingConfigurer ??
實現(xiàn) void configureTasks(ScheduledTaskRegistrar taskRegistrar); 方法,此方法的作用就是根據(jù)給定的 ScheduledTaskRegistrar 注冊 TaskScheduler 和特定的Task實例
@Component
public class CompleteScheduleConfig implements SchedulingConfigurer {
@Autowired
@SuppressWarnings("all")
CronMapper cronMapper;
/**
* 執(zhí)行定時任務(wù).
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任務(wù)內(nèi)容(Runnable)
() -> System.out.println("執(zhí)行動態(tài)定時任務(wù)1: " + LocalDateTime.now().toLocalTime()+",此任務(wù)執(zhí)行周期由數(shù)據(jù)庫中的cron表達式?jīng)Q定"),
//2.設(shè)置執(zhí)行周期(Trigger)
triggerContext -> {
//2.1 從數(shù)據(jù)庫獲取執(zhí)行周期
String cron = cronMapper.getCron1();
//2.2 合法性校驗.
if (cron!=null) {
// Omitted Code ..
}
//2.3 返回執(zhí)行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}2.4、效果

注意:當你修改了任務(wù)執(zhí)行周期后,生效時間為執(zhí)行完最近一次任務(wù)后。這一點是需要注意的,用生活中的例子理解就是我們?nèi)∠娫捒ǖ奶撞鸵惨聜€月生效,含義是一樣的。
三、實現(xiàn)設(shè)置時間定時任務(wù)
通常業(yè)務(wù)場景是我前言中說的那樣,是一次性的定時任務(wù)。如:我設(shè)置了我寫的這篇文章的發(fā)布時間為今天下午的兩點,執(zhí)行完就刪除沒有了。一次性的。
實現(xiàn)主要依靠于 TaskScheduler 的 ScheduledFuture<?> schedule(Runnable task, Trigger trigger); 方法來實現(xiàn)。其本質(zhì)和動態(tài)定時任務(wù)的實現(xiàn)是一樣的。
3.1、實現(xiàn)重點
代碼中都含有注解,不多做闡述。
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;
}
/**
* 查看已開啟但還未執(zhí)行的動態(tài)任務(wù)
* @return
*/
public List<String> getTaskList() {
return taskList;
}
/**
* 添加一個動態(tài)任務(wù)
*
* @param task
* @return
*/
public boolean add(Task task) {
// 此處的邏輯是 ,如果當前已經(jīng)有這個名字的任務(wù)存在,先刪除之前的,再添加現(xiàn)在的。(即重復(fù)就覆蓋)
if (null != taskMap.get(task.getName())) {
stop(task.getName());
}
// hutool 工具包下的一個轉(zhuǎn)換類型工具類 好用的很
ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
Date startTime = converterRegistry.convert(Date.class, task.getStart());
// schedule :調(diào)度給定的Runnable ,在指定的執(zhí)行時間調(diào)用它。
//一旦調(diào)度程序關(guān)閉或返回的ScheduledFuture被取消,執(zhí)行將結(jié)束。
//參數(shù):
//任務(wù) – 觸發(fā)器觸發(fā)時執(zhí)行的 Runnable
//startTime – 任務(wù)所需的執(zhí)行時間(如果這是過去,則任務(wù)將立即執(zhí)行,即盡快執(zhí)行)
ScheduledFuture<?> schedule = syncScheduler.schedule(getRunnable(task), startTime);
taskMap.put(task.getName(), schedule);
taskList.add(task.getName());
return true;
}
/**
* 運行任務(wù)
*
* @param task
* @return
*/
public Runnable getRunnable(Task task) {
return () -> {
log.info("---動態(tài)定時任務(wù)運行---");
try {
System.out.println("此時時間==>" + LocalDateTime.now());
System.out.println("task中設(shè)定的時間==>" + task);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("---end--------");
};
}
/**
* 停止任務(wù)
*
* @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);
// 這里給線程設(shè)置名字,主要是為了在項目能夠更快速的定位錯誤。
syncScheduler.setThreadGroupName("syncTg");
syncScheduler.setThreadNamePrefix("syncThread-");
syncScheduler.initialize();
return syncScheduler;
}
}3.3、業(yè)務(wù)代碼
這里需要注意一個點,我給項目中的 LocalDateTime 做了類型轉(zhuǎn)換。這里沒貼出來(主要是復(fù)制以前的代碼遺留下來的,源碼中都有)
大家簡單使用,可以直接用注解 標注在 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;
}
/**
* 查看已開啟但還未執(zhí)行的動態(tài)任務(wù)
* @return
*/
@GetMapping
public List<String> getStartingDynamicTask(){
return dynamicTask.getTaskList();
}
/**
* 開啟一個動態(tài)任務(wù)
* @param task
* @return
*/
@PostMapping("/dynamic")
public String startDynamicTask(@RequestBody Task task){
// 將這個添加到動態(tài)定時任務(wù)中去
dynamicTask.add(task);
return "動態(tài)任務(wù):"+task.getName()+" 已開啟";
}
/**
* 根據(jù)名稱 停止一個動態(tài)任務(wù)
* @param name
* @return
*/
@DeleteMapping("/{name}")
public String stopDynamicTask(@PathVariable("name") String name){
// 將這個添加到動態(tài)定時任務(wù)中去
if(!dynamicTask.stop(name)){
return "停止失敗,任務(wù)已在進行中.";
}
return "任務(wù)已停止";
}
}簡單封裝的一個實體類:
/**
* @Author: crush
* @Date: 2021-07-29 15:35
* version 1.0
*/
@Data
@Accessors(chain = true) // 方便鏈式編寫 習(xí)慣所然
public class Task {
/**
* 動態(tài)任務(wù)名曾
*/
private String name;
/**
* 設(shè)定動態(tài)任務(wù)開始時間
*/
private LocalDateTime start;
}3.4、效果
開啟一個動態(tài)任務(wù):

查看開啟還未執(zhí)行的動態(tài)任務(wù):

執(zhí)行結(jié)果:

和我們代碼中是一模一樣的。

停止任務(wù):


再去查看就是已經(jīng)停止的拉
到此這篇關(guān)于SpringBoot實現(xiàn)固定和動態(tài)定時任務(wù)的三種方法的文章就介紹到這了,更多相關(guān)SpringBoot 固定和動態(tài)定時任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot定時任務(wù)兩種(Spring Schedule 與 Quartz 整合 )實現(xiàn)方法
- SpringBoot中實現(xiàn)定時任務(wù)的4種方式詳解
- SpringBoot中實現(xiàn)定時任務(wù)的幾種方式
- SpringBoot2 task scheduler 定時任務(wù)調(diào)度器四種方式
- SpringBoot下使用定時任務(wù)的方式全揭秘(6種)
- Springboot實現(xiàn)定時任務(wù)的4種方式舉例詳解
- SpringBoot實現(xiàn)定時任務(wù)的三種方式小結(jié)
- SpringBoot最新定時任務(wù)的7種實現(xiàn)方案
相關(guān)文章
Netty分布式NioSocketChannel注冊到selector方法解析
這篇文章主要為大家介紹了Netty分布式源碼分析NioSocketChannel注冊到selector方法的解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
spring?boot整合mongo查詢converter異常排查記錄
這篇文章主要為大家介紹了spring?boot整合mongo查詢時拋出converter異常的排查解決記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03
打開.properties中文顯示unicode編碼問題以及解決
這篇文章主要介紹了打開.properties中文顯示unicode編碼問題以及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
Java?數(shù)據(jù)結(jié)構(gòu)進階二叉樹題集下
二叉樹可以簡單理解為對于一個節(jié)點來說,最多擁有一個上級節(jié)點,同時最多具備左右兩個下級節(jié)點的數(shù)據(jù)結(jié)構(gòu)。本文將帶你通過實際題目來熟練掌握2022-04-04
Java簡單實現(xiàn)對一串數(shù)字采用相應(yīng)的加密策略后傳輸
下面小編就為大家?guī)硪黄狫ava簡單實現(xiàn)對一串數(shù)字采用相應(yīng)的加密策略后傳輸。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09
spring?boot對敏感信息進行加解密的項目實現(xiàn)
本文主要介紹了spring?boot對敏感信息進行加解密的項目實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04

