首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 定時任務兩大實作方式詳解

     編輯:Java 相關知識

Spring 定時任務:@Scheduled 與 Quartz 完整比較

Spring 提供兩種主流定時任務實作方式:內建的 @Scheduled 註解與整合 Quartz 排程器。本文詳細比較兩者特性、配置與適用場景。

方式一:Spring @Scheduled (簡單、輕量)

啟用配置

@Configuration
@EnableScheduling  // 關鍵:啟用排程支援
public class SchedulerConfig { }

基本用法

@Component
public class SimpleScheduledTasks {
    private static final Logger log = LoggerFactory.getLogger(SimpleScheduledTasks.class);
    
    // 固定延遲:上次執行結束後 5 秒再執行
    @Scheduled(fixedDelay = 5000)
    public void fixedDelayTask() {
        log.info("fixedDelay 執行時間: {}", LocalTime.now());
    }
    
    // 固定頻率:每 5 秒執行一次 (無視執行耗時)
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() {
        log.info("fixedRate 執行時間: {}", LocalTime.now());
    }
    
    // 初始延遲 2 秒,之後固定頻率
    @Scheduled(initialDelay = 2000, fixedRate = 5000)
    public void initialDelayTask() { /* ... */ }
    
    // Cron 運算式:每天凌晨 2:30 執行
    @Scheduled(cron = "0 30 2 * * ?")
    public void cronTask() {
        log.info("Cron 任務執行: {}", LocalDateTime.now());
    }
}

Cron 運算式詳解

秒 分 時 日 月 周 [年]
*  *  *  *  *  ?     每秒執行
0  *  *  *  *  ?     每分鐘執行
0  0  *  *  *  ?     每小時執行
0  0  2  *  *  ?     每天凌晨 2 點
0  30 2  *  *  ?     每天 2:30
0  0  2  ?  *  MON   每週一凌晨 2 點
0  0  2  1  *  ?     每月 1 號凌晨 2 點

@Scheduled 進階配置

@Scheduled(
    cron = "0 0/5 * * * ?",           // Cron 運算式
    zone = "Asia/Taipei",             // 時區 (預設系統時區)
    fixedDelay = 5000,                // 固定延遲 (ms)
    fixedRate = 5000,                 // 固定頻率 (ms)
    initialDelay = 1000               // 初始延遲 (ms)
)
public void advancedTask() { /* ... */ }

方式二:Quartz 整合 (功能強大、企業級)

依賴引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

核心組件

組件說明
Job實作 org.quartz.Job 介面,定義任務邏輯
JobDetail任務描述:名稱、群組、持久化資料
Trigger觸發器:SimpleTrigger (簡單)、CronTrigger (Cron)
Scheduler排程器:管理 Job 與 Trigger 的註冊、啟動、暫停

完整實作範例

// 1. 定義 Job
@Component
public class QuartzJob implements Job {
    private static final Logger log = LoggerFactory.getLogger(QuartzJob.class);
    
    @Override
    public void execute(JobExecutionContext context) {
        JobDataMap data = context.getMergedJobDataMap();
        String param = data.getString("customParam");
        log.info("Quartz 任務執行: param={}, time={}", param, LocalDateTime.now());
    }
}

// 2. 配置排程
@Configuration
public class QuartzConfig {
    @Autowired private SchedulerFactoryBean schedulerFactory;
    
    @PostConstruct
    public void init() throws SchedulerException {
        Scheduler scheduler = schedulerFactory.getScheduler();
        
        // 定義 JobDetail
        JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
            .withIdentity("myJob", "group1")
            .usingJobData("customParam", "Hello Quartz")
            .storeDurably()
            .build();
        
        // 定義 Cron Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("myTrigger", "group1")
            .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")) // 每 2 分鐘
            .build();
        
        // 註冊並啟動
        scheduler.scheduleJob(jobDetail, trigger);
        if (!scheduler.isStarted()) scheduler.start();
    }
}

動態管理 API

@RestController
@RequiredArgsConstructor
public class QuartzController {
    private final Scheduler scheduler;
    
    @PostMapping("/jobs/{name}/pause")
    public void pauseJob(@PathVariable String name) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(name, "group1"));
    }
    
    @PostMapping("/jobs/{name}/resume")
    public void resumeJob(@PathVariable String name) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(name, "group1"));
    }
    
    @DeleteMapping("/jobs/{name}")
    public void deleteJob(@PathVariable String name) throws SchedulerException {
        scheduler.deleteJob(JobKey.jobKey(name, "group1"));
    }
    
    @PutMapping("/jobs/{name}/reschedule")
    public void rescheduleJob(@PathVariable String name, @RequestParam String cron) 
            throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(name, "group1");
        CronTrigger newTrigger = TriggerBuilder.newTrigger()
            .withIdentity(triggerKey)
            .withSchedule(CronScheduleBuilder.cronSchedule(cron))
            .build();
        scheduler.rescheduleJob(triggerKey, newTrigger);
    }
}

兩大方式深度比較

比較項目@ScheduledQuartz
複雜度低 (註解驅動)中高 (需配置 Job/Trigger)
動態管理不支援 (需重啟修改)完整支援 (Runtime 新增/修改/刪除)
叢集支援不支援原生支援 (資料庫鎖機制)
持久化無JDBC JobStore 完整支援
Misfire 處理無豐富策略 (忽略、立即執行、智能策略)
監控管理僅靠日誌可整合 Quartz Manager/UI
適用場景簡單固定任務、單機應用企業級、叢集、動態排程、需持久化

選型建議

✅ 選擇 @Scheduled 當:

  • 任務固定、啟動後不變
  • 單機部署、無叢集需求
  • 團隊較小、追求開發速度
  • 任務邏輯簡單、執行時間短

✅ 選擇 Quartz 當:

  • 需動態新增/修改/刪除任務
  • 叢集環境、高可用需求
  • 任務需持久化、重啟後恢復
  • 複雜排程規則、Misfire 處理
  • 需圖形化管理介面

Spring 定時任務從簡單的 @Scheduled 到強大的 Quartz 整合,滿足不同層級的排程需求。理解兩者差異與適用場景,能為專案選擇最合適的技術方案,避免過度設計或功能不足。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved