Java動態(tài)添加Scheduled的實現(xiàn)方式
引言
在Java中,動態(tài)添加??Scheduled???定時任務(wù)可以通過多種方式實現(xiàn),其中最常見的是使用Spring框架提供的??@Scheduled???注解結(jié)合??SchedulingConfigurer???接口,以及通過??ThreadPoolTaskScheduler???來管理任務(wù)的調(diào)度。此外,還可以利用??ScheduledExecutorService??來創(chuàng)建和管理定時任務(wù)。下面將詳細(xì)介紹如何在Spring環(huán)境中動態(tài)地添加、修改和取消定時任務(wù)。
使用??SchedulingConfigurer???和??ThreadPoolTaskScheduler??
Spring提供了??SchedulingConfigurer???接口,它允許開發(fā)者自定義調(diào)度器配置,從而能夠更靈活地控制定時任務(wù)的行為。要實現(xiàn)動態(tài)添加定時任務(wù),首先需要創(chuàng)建一個實現(xiàn)了??SchedulingConfigurer???接口的配置類,并在這個類中注入??ScheduledTaskRegistrar???實例。這樣做的好處是可以直接訪問到??ScheduledTaskRegistrar??,進而可以調(diào)用其提供的API來注冊新的任務(wù)或更新已有的任務(wù)。
@Slf4j
@EnableScheduling
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final ScheduledTaskRegistrar taskRegistrar;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
ThreadPoolTaskScheduler taskScheduler = threadPoolTaskScheduler();
taskRegistrar.setScheduler(taskScheduler);
}
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1);
scheduler.setThreadNamePrefix("scheduler-");
scheduler.setRemoveOnCancelPolicy(true);
return scheduler;
}
}
接下來,在應(yīng)用程序啟動后或者根據(jù)業(yè)務(wù)邏輯的需求,可以通過??taskRegistrar??來添加新的定時任務(wù)。例如,我們可以定義一個方法來創(chuàng)建并調(diào)度一個新的Cron任務(wù):
@Autowired
private ScheduledTaskRegistrar taskRegistrar;
public ScheduledTask addCronTask(String cronExpression, Runnable task) {
CronTask cronTask = new CronTask(task, new CronTrigger(cronExpression));
return taskRegistrar.scheduleCronTask(cronTask);
}
這里,??addCronTask???方法接收兩個參數(shù):一個是cron表達式,用于指定任務(wù)的執(zhí)行時間;另一個是??Runnable???類型的任務(wù)對象,表示具體要執(zhí)行的操作。該方法返回一個??ScheduledTask??實例,可用于后續(xù)的任務(wù)管理和取消操作。
動態(tài)修改和取消定時任務(wù)
除了添加新的定時任務(wù)外,我們還可能需要在運行時修改現(xiàn)有任務(wù)的執(zhí)行周期或者完全取消某個任務(wù)。對于基于??ScheduledTaskRegistrar???創(chuàng)建的任務(wù),可以通過保存每個任務(wù)對應(yīng)的??ScheduledTask??對象來實現(xiàn)這一點。當(dāng)需要更改任務(wù)的執(zhí)行周期時,可以先取消舊的任務(wù),然后重新創(chuàng)建一個新的任務(wù):
public void updateCronTask(ScheduledTask oldTask, String newCronExpression, Runnable task) {
if (oldTask != null) {
oldTask.cancel(true);
}
addCronTask(newCronExpression, task);
}
如果只是想暫停某個任務(wù)而不立即刪除它,可以調(diào)用??ScheduledTask???的??cancel(boolean mayInterruptIfRunning)???方法,傳入??true??表示允許中斷正在執(zhí)行的任務(wù)。之后,可以根據(jù)需要決定是否重新啟動該任務(wù)。
使用??ScheduledExecutorService??
除了上述基于Spring的方式之外,??ScheduledExecutorService???也是一種非常有效的手段,特別是在不需要依賴Spring上下文的情況下。??ScheduledExecutorService???提供了簡單易用的API來安排命令在未來某一時刻執(zhí)行,既可以是一次性的也可以是周期性的。下面是一個簡單的例子,展示了如何使用??ScheduledExecutorService??來動態(tài)添加定時任務(wù):
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DynamicScheduledTaskExample {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
// 添加一個每5秒執(zhí)行一次的任務(wù)
scheduler.scheduleAtFixedRate(() -> System.out.println("Executing task at fixed rate"), 0, 5, TimeUnit.SECONDS);
// 模擬一段時間后的動態(tài)添加新任務(wù)
try {
Thread.sleep(10000); // 等待10秒
} catch (InterruptedException e) {
e.printStackTrace();
}
// 添加一個每10秒執(zhí)行一次的新任務(wù)
scheduler.scheduleAtFixedRate(() -> System.out.println("Executing another task at fixed rate"), 0, 10, TimeUnit.SECONDS);
}
}
在這個例子中,我們首先創(chuàng)建了一個包含兩個線程的??ScheduledExecutorService???實例。然后,我們使用??scheduledAtFixedRate???方法來安排兩個不同的任務(wù),它們分別以5秒和10秒的時間間隔重復(fù)執(zhí)行。需要注意的是,與Spring中的??@Scheduled???不同,??ScheduledExecutorService??不會自動管理任務(wù)的生命周期,因此必須手動確保資源的正確釋放。
結(jié)合數(shù)據(jù)庫持久化
為了使定時任務(wù)更加健壯和易于管理,通常會將任務(wù)的相關(guān)信息(如cron表達式、狀態(tài)等)存儲在數(shù)據(jù)庫中。這樣不僅可以方便地對任務(wù)進行查詢和維護,而且可以在應(yīng)用重啟后恢復(fù)之前的狀態(tài)。例如,可以設(shè)計一張名為??schedule_setting??的表來保存定時任務(wù)的元數(shù)據(jù):
CREATE TABLE IF NOT EXISTS `schedule_setting` (
`job_id` int NOT NULL AUTO_INCREMENT COMMENT '任務(wù)ID',
`bean_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'bean名稱',
`method_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '方法名稱',
`method_params` varchar(8192) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '方法參數(shù)',
`cron_expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'cron表達式',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '備注',
`job_status` tinyint(1) DEFAULT NULL COMMENT '狀態(tài)(1為啟用,0為停用)',
`create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時間',
`update_time` datetime DEFAULT NULL COMMENT '修改時間',
PRIMARY KEY (`job_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
通過這種方式,可以輕松地實現(xiàn)定時任務(wù)的持久化,并且可以在需要時從數(shù)據(jù)庫讀取任務(wù)配置,動態(tài)地加載或更新任務(wù)。
綜上所述,無論是使用Spring內(nèi)置的支持還是借助??ScheduledExecutorService???,都可以有效地實現(xiàn)在Java應(yīng)用程序中動態(tài)添加、修改和取消定時任務(wù)的功能。選擇哪種方式取決于具體的項目需求和技術(shù)棧。如果你已經(jīng)在使用Spring Boot,那么推薦采用前者,因為它與框架集成得更好,同時也提供了更多的特性和便利性。而對于那些不依賴于Spring的應(yīng)用程序來說,??ScheduledExecutorService??則是一個輕量級且高效的選擇。
以上就是Java動態(tài)添加Scheduled的實現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于Java動態(tài)添加Scheduled的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis-plus分頁查詢total=0問題及解決方案
這篇文章主要介紹了mybatis-plus分頁查詢total=0問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2026-03-03
java實現(xiàn)微信公眾平臺發(fā)送模板消息的示例代碼
這篇文章主要介紹了java實現(xiàn)微信公眾平臺發(fā)送模板消息的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
prometheus數(shù)據(jù)遠程寫入elasticsearch方式
這篇文章主要介紹了prometheus數(shù)據(jù)遠程寫入elasticsearch方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-06-06
慢sql提前分析預(yù)警和動態(tài)sql替換-Mybatis-SQL
為防止慢SQL問題而開發(fā)的MyBatis組件,該組件能夠在開發(fā)、測試階段自動分析SQL語句,并在出現(xiàn)慢SQL問題時通過Ducc配置實現(xiàn)動態(tài)替換,從而快速止損2025-05-05

