Quartz 是 Java 生態中事實標準的任務調度框架。本文提煉官方文檔精華,結合實戰經驗,從「三大核心組件」到「Web 容器整合」、從「參數傳遞」到「監聽器鏈」,為你構建完整的 Quartz 知識體系,助你在半小時內從入門到可用。
// 1. 定義任務(業務邏輯載體)
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1").build();
// 2. 定義觸發器(時間規則)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // 每 5 秒
.build();
// 3. 調度器:綁定並啟動
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
scheduler.start(); // 必須調用才真正跑起來
// 應用關閉時
scheduler.shutdown();
JobDetail 是「任務定義」(含名稱/組/參數),HelloJob 才是實際 execute() 邏輯。一個 Job 類可對應多個 JobDetail。start() 前後掛任務均可,內部維護線程池與調度邏輯。import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
// 之後直接 newJob()、newTrigger()、cronSchedule() 鏈式調用
強烈建議統一使用 CronTrigger,其表達式能力幾乎覆蓋所有業務場景,減少認知負擔。
// JobDetail 級參數(所有 Trigger 共享)
jobDetail.getJobDataMap().put("bizKey", JSON.toJSONString(bizObj));
// Trigger 級參數(覆蓋/補充 JobDetail 參數)
trigger.getJobDataMap().put("runId", UUID.randomUUID().toString());
// 執行時統一獲取(自動合併)
context.getMergedJobDataMap().getString("bizKey");
建議所有值統一序列化為 String,避免類加載器隔離導致反序列化失敗。
// 實現自定義監聽器
public class MetricsJobListener extends JobListenerSupport {
@Override public void jobToBeExecuted(JobExecutionContext ctx) { /* 記錄開始時間 */ }
@Override public void jobWasExecuted(JobExecutionContext ctx, JobExecutionException e) {
// 記錄耗時、成功/失敗、異常堆棧
}
}
// 註冊(支援針對特定 Job/Group)
scheduler.getListenerManager().addJobListener(listener, allJobs());
scheduler.getListenerManager().addTriggerListener(triggerListener);
執行順序鏈:
TriggerListener.triggerFired → JobListener.jobToBeExecuted → Job.execute → JobListener.jobWasExecuted → TriggerListener.triggerComplete
利用此鏈可實現:執行指標收集、失敗告警、業務狀態流轉等橫切關注點。
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>config-file</param-name>
<param-value>/quartz.properties</param-value>
</init-param>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
org.quartz.scheduler.instanceName = MainScheduler
org.quartz.scheduler.instanceId = instance_one # 集群時每節點唯一
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = qzDS
org.quartz.jobStore.useProperties = true # 強制 String 參數,避免序列化坑
org.quartz.jobStore.isClustered = false # 集群改 true
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
org.quartz.dataSource.qzDS.user = root
org.quartz.dataSource.qzDS.password = 123456
org.quartz.dataSource.qzDS.maxConnections = 30
SchedulerFactory sf = (SchedulerFactory) servletContext
.getAttribute(QuartzInitializerServlet.QUARTZ_FACTORY_KEY);
Scheduler scheduler = sf.getScheduler(); // 已自動 start()
封裝 JobManager 提供:addJob()、pauseJob()、resumeJob()、deleteJob()、triggerJobNow() 等統一入口,內部處理 JobKey/TriggerKey 構建與異常轉換,對上層業務屏蔽 Quartz API 細節。
instanceId 唯一,isClustered=trueJobExecutionException 可配合 refireImmediately 實現重試策略掌握以上內容,你已具備在生產環境落地 Quartz 的完整能力。更多高級特性(如 Calendar 排除節假日、插件擴展、集群故障轉移)請參考官方文檔深入探索。