最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot運行時修改定時任務Cron表達式的實現(xiàn)方案

 更新時間:2025年06月30日 08:43:10   作者:風象南  
在項目開發(fā)中,定時任務是一個常見的需求,SpringBoot通過@Scheduled注解提供了簡便的定時任務實現(xiàn)方式,但默認情況下,一旦應用啟動,定時任務的Cron表達式就無法動態(tài)調(diào)整,本文將介紹如何在SpringBoot應用運行期間動態(tài)修改定時任務的Cron表達式,需要的朋友可以參考下

一、引言

在項目開發(fā)中,定時任務是一個常見的需求。Spring Boot 通過 @Scheduled 注解提供了簡便的定時任務實現(xiàn)方式,但默認情況下,一旦應用啟動,定時任務的 Cron 表達式就無法動態(tài)調(diào)整。

然而,在實際業(yè)務場景中,我們常常需要根據(jù)運行狀態(tài)或用戶配置動態(tài)調(diào)整定時任務的執(zhí)行頻率。

本文將介紹如何在 Spring Boot 應用運行期間動態(tài)修改定時任務的 Cron 表達式,實現(xiàn)定時任務的靈活調(diào)度。

二、Spring 定時任務機制概述

2.1 Spring 定時任務的實現(xiàn)方式

Spring Boot 支持三種定時任務的實現(xiàn)方式:

@Scheduled 注解:最簡單的方式,直接在方法上添加注解 SchedulingConfigurer 接口:通過實現(xiàn)該接口,可以進行更靈活的配置 TaskScheduler 接口:最底層的 API,提供最大的靈活性

傳統(tǒng)的 @Scheduled 注解使用示例:

@Component
public class ScheduledTasks {
    
    @Scheduled(cron = "0 0/5 * * * ?")  // 每5分鐘執(zhí)行一次
    public void executeTask() {
        System.out.println("定時任務執(zhí)行,時間:" + new Date());
    }
}

2.2 @Scheduled 注解的局限性

雖然 @Scheduled 注解使用簡便,但它存在明顯的局限性:

  1. Cron 表達式在編譯時就確定,運行時無法修改
  2. 無法根據(jù)條件動態(tài)啟用或禁用定時任務
  3. 無法在運行時動態(tài)添加新的定時任務
  4. 無法獲取定時任務的執(zhí)行狀態(tài)

這些局限使得 @Scheduled 注解不適合需要動態(tài)調(diào)整的場景。

三、動態(tài)定時任務的實現(xiàn)方案

要實現(xiàn)定時任務的動態(tài)調(diào)整,我們有幾種可行的方案:

3.1 基于 SchedulingConfigurer 接口的實現(xiàn)

這是最常用的方式,通過實現(xiàn) SchedulingConfigurer 接口,我們可以獲取 TaskSchedulerScheduledTaskRegistrar,從而實現(xiàn)定時任務的動態(tài)管理。

以下是基本實現(xiàn)步驟:

步驟 1:創(chuàng)建任務配置類

package com.example.scheduler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;

import java.util.Date;

@Configuration
@EnableScheduling
public class DynamicScheduleConfig implements SchedulingConfigurer {
    
    @Autowired
    private CronRepository cronRepository;  // 用于存儲和獲取Cron表達式
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskScheduler());
        
        // 從數(shù)據(jù)庫或配置中心獲取初始Cron表達式
        String initialCron = cronRepository.getCronByTaskName("sampleTask");
        
        // 添加可動態(tài)修改的定時任務
        taskRegistrar.addTriggerTask(
            // 定時任務的執(zhí)行邏輯
            () -> {
                System.out.println("動態(tài)定時任務執(zhí)行,時間:" + new Date());
            },
            // 定時任務觸發(fā)器,可根據(jù)需要返回下次執(zhí)行時間
            triggerContext -> {
                // 每次任務觸發(fā)時,重新獲取Cron表達式
                String cron = cronRepository.getCronByTaskName("sampleTask");
                CronTrigger trigger = new CronTrigger(cron);
                return trigger.nextExecution(triggerContext);
            }
        );
    }
    
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);  // 設置線程池大小
        scheduler.setThreadNamePrefix("task-");
        scheduler.initialize();
        return scheduler;
    }
}

步驟 2:創(chuàng)建存儲和管理 Cron 表達式的組件

@Repository
public class CronRepository {
    
    // 這里可以連接數(shù)據(jù)庫或配置中心,本例使用內(nèi)存存儲簡化演示
    private final Map<String, String> cronMap = new ConcurrentHashMap<>();
    
    public CronRepository() {
        // 設置初始值
        cronMap.put("sampleTask", "0 0/1 * * * ?");  // 默認每分鐘執(zhí)行一次
    }
    
    public String getCronByTaskName(String taskName) {
        return cronMap.getOrDefault(taskName, "0 0/1 * * * ?");
    }
    
    public void updateCron(String taskName, String cron) {
        // 驗證cron表達式的有效性
        try {
            new CronTrigger(cron);
            cronMap.put(taskName, cron);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid cron expression: " + cron, e);
        }
    }
}

步驟 3:創(chuàng)建 REST API 用于修改 Cron 表達式

@RestController
@RequestMapping("/scheduler")
public class SchedulerController {
    
    @Autowired
    private CronRepository cronRepository;
    
    @GetMapping("/cron/{taskName}")
    public Map<String, String> getCron(@PathVariable String taskName) {
        Map<String, String> result = new HashMap<>();
        result.put("taskName", taskName);
        result.put("cron", cronRepository.getCronByTaskName(taskName));
        return result;
    }
    
    @PutMapping("/cron/{taskName}")
    public Map<String, String> updateCron(
            @PathVariable String taskName, 
            @RequestParam String cron) {
        cronRepository.updateCron(taskName, cron);
        
        Map<String, String> result = new HashMap<>();
        result.put("taskName", taskName);
        result.put("cron", cron);
        result.put("message", "Cron expression updated successfully");
        return result;
    }
}

3.2 使用 Spring 的 TaskScheduler 直接管理定時任務

我們可以直接使用 TaskScheduler 接口進行定時任務的細粒度控制:

package com.example.scheduler;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

@Service
public class AdvancedTaskScheduler {
    
    @Autowired
    private TaskScheduler taskScheduler;
    
    @Autowired
    private CronRepository cronRepository;
    
    // 維護所有調(diào)度任務
    private final Map<String, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>();
    
    @Data
    @AllArgsConstructor
    private static class ScheduledTask {
        private String taskName;
        private String cron;
        private Runnable runnable;
        private ScheduledFuture<?> future;
        private boolean running;
    }
    
    /**
     * 注冊一個新的定時任務
     */
    public void registerTask(String taskName, Runnable runnable) {
        // 判斷任務是否已存在
        if (scheduledTasks.containsKey(taskName)) {
            throw new IllegalArgumentException("Task with name " + taskName + " already exists");
        }
        String cron = cronRepository.getCronByTaskName(taskName);
        ScheduledFuture<?> future = taskScheduler.schedule(
            runnable,
            triggerContext -> {
                // 動態(tài)獲取最新的cron表達式
                String currentCron = cronRepository.getCronByTaskName(taskName);
                return new CronTrigger(currentCron).nextExecution(triggerContext);
            }
        );
        
        scheduledTasks.put(taskName, new ScheduledTask(taskName, cron, runnable, future, true));
    }
    
    /**
     * 更新任務的Cron表達式
     */
    public void updateTaskCron(String taskName, String cron) {
        // 更新數(shù)據(jù)庫/配置中心中的cron表達式
        cronRepository.updateCron(taskName, cron);
        
        // 重新調(diào)度任務
        ScheduledTask task = scheduledTasks.get(taskName);
        if (task != null) {
            // 取消現(xiàn)有任務
            task.getFuture().cancel(false);
            
            // 創(chuàng)建新任務
            ScheduledFuture<?> future = taskScheduler.schedule(
                task.getRunnable(),
                triggerContext -> {
                    return new CronTrigger(cron).nextExecution(triggerContext);
                }
            );
            
            // 更新任務信息
            task.setCron(cron);
            task.setFuture(future);
        }
    }
    
    /**
     * 暫停任務
     */
    public void pauseTask(String taskName) {
        ScheduledTask task = scheduledTasks.get(taskName);
        if (task != null && task.isRunning()) {
            task.getFuture().cancel(false);
            task.setRunning(false);
        }
    }
    
    /**
     * 恢復任務
     */
    public void resumeTask(String taskName) {
        ScheduledTask task = scheduledTasks.get(taskName);
        if (task != null && !task.isRunning()) {
            ScheduledFuture<?> future = taskScheduler.schedule(
                task.getRunnable(),
                triggerContext -> {
                    String currentCron = cronRepository.getCronByTaskName(taskName);
                    return new CronTrigger(currentCron).nextExecution(triggerContext);
                }
            );
            
            task.setFuture(future);
            task.setRunning(true);
        }
    }
    
    /**
     * 刪除任務
     */
    public void removeTask(String taskName) {
        ScheduledTask task = scheduledTasks.get(taskName);
        if (task != null) {
            task.getFuture().cancel(false);
            scheduledTasks.remove(taskName);
        }
    }
    
    /**
     * 獲取所有任務信息
     */
    public List<Map<String, Object>> getAllTasks() {
        return scheduledTasks.values().stream()
            .map(task -> {
                Map<String, Object> map = new HashMap<>();
                map.put("taskName", task.getTaskName());
                map.put("cron", task.getCron());
                map.put("running", task.isRunning());
                return map;
            })
            .collect(Collectors.toList());
    }
}

四、使用數(shù)據(jù)庫存儲 Cron 表達式

對于生產(chǎn)環(huán)境,我們需要確保定時任務的配置能夠持久化,將 CronRepository 修改為使用數(shù)據(jù)庫存儲

@Repository
public class DatabaseCronRepository implements CronRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public String getCronByTaskName(String taskName) {
        try {
            return jdbcTemplate.queryForObject(
                "SELECT cron FROM scheduled_tasks WHERE task_name = ?",
                String.class,
                taskName
            );
        } catch (EmptyResultDataAccessException e) {
            return "0 0/1 * * * ?";  // 默認值
        }
    }
    
    @Override
    public void updateCron(String taskName, String cron) {
        // 驗證cron表達式
        try {
            new CronTrigger(cron);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid cron expression: " + cron, e);
        }
        
        // 更新數(shù)據(jù)庫
        int updated = jdbcTemplate.update(
            "UPDATE scheduled_tasks SET cron = ? WHERE task_name = ?",
            cron, taskName
        );
        
        if (updated == 0) {
            // 如果記錄不存在,則插入
            jdbcTemplate.update(
                "INSERT INTO scheduled_tasks (task_name, cron) VALUES (?, ?)",
                taskName, cron
            );
        }
    }
}

數(shù)據(jù)庫表結(jié)構(gòu):

CREATE TABLE scheduled_tasks (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    task_name VARCHAR(100) NOT NULL UNIQUE,
    cron VARCHAR(100) NOT NULL,
    description VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

五、總結(jié)

在一些相對簡單的業(yè)務或項目或服務器資源有限的情況下,可以基于本文思路進行簡單擴展,即可實現(xiàn)定時任務管理,無需額外引入其他定時任務組件。

如果是一些相對復雜的項目對定時任務有更多需求和可靠性保證的要求,可以引入如xxl-job、ElasticJob等任務調(diào)度組件。

以上就是SpringBoot運行時修改定時任務Cron表達式的實現(xiàn)方案的詳細內(nèi)容,更多關于SpringBoot修改Cron表達式的資料請關注腳本之家其它相關文章!

相關文章

  • java中Unsafe的使用講解

    java中Unsafe的使用講解

    這篇文章主要介紹了java中Unsafe的使用講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SSM框架流程及原理分析

    SSM框架流程及原理分析

    本文給大家分享小編一些心得體會,主要是學習SSM框架之后的收獲吧,重點給大家介紹SSM框架流程以及原理分析,通過圖文實例相結(jié)合給大家介紹的非常詳細,需要的朋友參考下吧
    2021-06-06
  • Java實現(xiàn)四則混合運算代碼示例

    Java實現(xiàn)四則混合運算代碼示例

    這篇文章主要介紹了Java實現(xiàn)四則混合運算代碼示例,文中展示了詳細代碼,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10
  • SpringBoot整合Shiro的環(huán)境搭建教程

    SpringBoot整合Shiro的環(huán)境搭建教程

    這篇文章主要為大家詳細介紹了SpringBoot整合Shiro的環(huán)境搭建教程,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解一下
    2022-12-12
  • Spring實現(xiàn)泛型注入的示例詳解

    Spring實現(xiàn)泛型注入的示例詳解

    Spring?4.0版本中更新了很多新功能,其中比較重要的一個就是對帶泛型的Bean進行依賴注入的支持。本文將通過實例詳細講講Spring如何實現(xiàn)泛型注入,需要的可以參考一下
    2022-07-07
  • SpringBoot配置Spring?Security的實現(xiàn)示例

    SpringBoot配置Spring?Security的實現(xiàn)示例

    本文主要介紹了SpringBoot配置Spring?Security的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-10-10
  • SpringBoot統(tǒng)一異常處理的實用方案

    SpringBoot統(tǒng)一異常處理的實用方案

    在日常開發(fā)中,你一定見過這樣的代碼:代碼冗余、維護困難、前端對接痛苦、日志混亂,線上出問題還難定位,統(tǒng)一異常處理,就是用來解決這些問題的,今天這篇文章,帶你從零到一實現(xiàn)SpringBoot全局統(tǒng)一異常處理,需要的朋友可以參考下
    2026-03-03
  • Java JDK 1.8 lambda的用法詳解

    Java JDK 1.8 lambda的用法詳解

    這篇文章主要介紹了Java JDK 1.8 lambda的用法詳解,文中給大家提到了jdk 1.8 Lambda 表達式 遍歷數(shù)組的方法,需要的朋友可以參考下
    2019-09-09
  • MyBatis ORM映射方式示例詳解

    MyBatis ORM映射方式示例詳解

    MyBatis作為一種靈活且強大的ORM框架,提供了多種映射方式,包括基于XML的映射、基于注解的映射以及混合映射,這篇文章主要介紹了MyBatis ORM映射方式詳解,需要的朋友可以參考下
    2024-12-12
  • Mybatis使用命令生成逆向工程的方法

    Mybatis使用命令生成逆向工程的方法

    這篇文章主要介紹了Mybatis使用命令生成逆向工程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01

最新評論

天峨县| 西乌珠穆沁旗| 凤城市| 桂阳县| 石景山区| 靖江市| 西藏| 南阳市| 仁怀市| 凤山市| 乌海市| 阿坝| 佛冈县| 德阳市| 东平县| 衡南县| 海口市| 淅川县| 承德县| 恩平市| 金华市| 滁州市| 本溪市| 定日县| 饶河县| 兴安盟| 荆门市| 南城县| 台北市| 讷河市| 临汾市| 新安县| 无极县| 东平县| 南召县| 报价| 绥芬河市| 久治县| 吴桥县| 卢湾区| 德清县|