當應用需要:「每天凌晨 2 點跑對帳」、「每 5 分鐘同步第三方數據」、「每月最後一天發薪資單」—— 別再寫 while(true){sleep();} 了。**Quartz** 是成熟、開源、純 Java 的企業級任務調度框架,支援叢集、持久化、Cron 表達式、監聽器、插件化擴充,已被 Spring Boot、Elasticsearch、Kubernetes 等知名專案廣泛採用。
| 組件 | 職責 | 關鍵介面/類 |
|---|---|---|
| Job (作業) | 業務邏輯載體 | org.quartz.Job (單一方法 execute(JobExecutionContext)) |
| Trigger (觸發器) | 定義「何時跑」 | SimpleTrigger (間隔/次數), CronTrigger (Cron 表達式) |
| Scheduler (調度器) | 核心引擎,管理 Job/Trigger 生命週期、執行緒池、持久化 | org.quartz.Scheduler, StdSchedulerFactory |
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Spring Boot 整合更簡單:spring-boot-starter-quartz -->
@Slf4j
@DisallowConcurrentExecution // 禁止併發執行同一 Job 實例 (對應 StatefulJob)
public class FtpSyncJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getMergedJobDataMap();
String ftpHost = dataMap.getString("ftpHost");
int port = dataMap.getInt("port");
// 業務邏輯:連線 FTP、下載檔案、解析入庫、發送通知...
log.info("FTP 同步完成: host={}, port={}", ftpHost, port);
}
}
@Configuration
public class QuartzConfig {
@Bean
public JobDetail ftpSyncJobDetail() {
return JobBuilder.newJob(FtpSyncJob.class)
.withIdentity("ftpSyncJob", "syncGroup")
.usingJobData("ftpHost", "files.example.com")
.usingJobData("port", 21)
.storeDurably() // 無 Trigger 也保留
.build();
}
@Bean
public Trigger ftpSyncTrigger(JobDetail ftpSyncJobDetail) {
// 每天 02:00 執行
return TriggerBuilder.newTrigger()
.forJob(ftpSyncJobDetail)
.withIdentity("ftpSyncTrigger", "syncGroup")
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 0))
.build();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(Trigger ftpSyncTrigger, JobDetail ftpSyncJobDetail) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setTriggers(ftpSyncTrigger);
factory.setJobDetails(ftpSyncJobDetail);
factory.setOverwriteExistingJobs(true);
factory.setStartupDelay(30); // 應用啟動 30 秒後啟動調度器
return factory;
}
}
生產環境建議將 Job/Trigger 定義外部化至資料庫 (JDBC JobStore),支援動態新增/修改/暫停/刪除任務,無需重新部署。Spring Boot 整合 Quartz 只需配置 spring.quartz.job-store-type=jdbc 並提供 DataSource,自動建表腳本在 org/quartz/impl/jdbcjobtables/。
| 類型 | 適用場景 | 優/缺點 | |
|---|---|---|---|
RAMJobStore | 開發、測試、單節點、任務少、可容忍重啟丟失 | 極快、零配置 / 非持久、無法叢集 | |
JobStoreTX | 獨立應用、自管事務 | 持久化、支援叢集 / 需資料庫、效能稍低 | |
JobStoreCMT | Java EE 容器、容器管事務 (JTA) | 整合容器事務 / 配置複雜 |
| 框架 | 定位 | 優勢 | 劣勢 |
|---|---|---|---|
| Quartz | 通用調度、叢集、持久化 | 成熟穩定、Spring 整合深、功能全 | API 略顯老舊、配置相對繁瑣 |
| Spring @Scheduled | 輕量級、單體應用 | 零配置、註解驅動、Spring 原生 | 無持久化、無叢集、無動態管理、單點故障 |
| XXL-JOB | 分散式任務調度平台 | Web 控制台、分片廣播、故障轉移、多語言 | 需部署獨立調度中心、學習成本 |
| Elastic-Job | 分散式叢集調度 | 基於 Quartz/ZK、分片彈性、運維平台 | 社區活躍度下降、ShardingSphere 整合為主 |
選型建議:單體/微服務少量定時任務 → @Scheduled;需持久化、叢集、動態管理、審計 → **Quartz**;大規模分散式、運維平台化、多語言 → **XXL-JOB / PowerJob**。