1. 概述
Quartz 具有模塊化架構,由 Job、JobDetail、Trigger 和 Scheduler 等關鍵組件組成,我們可以根據需要組合它們。 儘管我們將使用 Spring 來管理應用程序,但每個組件都可以使用 Quartz 的便捷類或 Spring 的方式進行配置。 為了完整性,我們將在適當的時候查看這兩種方法,但我們會選擇最適合的方法。 現在讓我們一次構建一個組件。
在本教程中,我們將使用 Spring 構建一個簡單的 Quartz 調度器,目標是輕鬆配置新的定時任務。
2. 作業 (Job) 和 JobDetail
在定義 Quartz 作業的第一步是創建任務本身。我們通過實現 Job 接口,然後用 JobDetail 將其包裹,從而提供作業實例的元數據來實現。
2.1. 任務
該API提供了一個任務接口,它只有一個方法,execute。必須由包含實際要執行的工作的類實現,即任務。當任務觸發時,調度器會調用execute方法,並將一個JobExecutionContext對象傳遞給它。
JobExecutionContext為任務提供關於其運行時環境的信息,包括對調度器的句柄、對觸發器的句柄以及任務的JobDetail對象。
在這個快速示例中,任務將任務委派給服務類:
@Component
public class SampleJob implements Job {
@Autowired
private SampleJobService jobService;
public void execute(JobExecutionContext context) throws JobExecutionException {
jobService.executeSampleJob();
}
}
2.2. JobDetail
雖然 Job 是核心工作引擎,但 Quartz 不會存儲實際的 Job 類的實例。相反,我們可以使用 JobDetail 類定義 Job 實例。Job 的類必須提供給 JobDetail,以便它知道要執行的 Job 的類型。
2.3. Quartz
The Quartz
@Bean
public JobDetail jobDetail() {
return JobBuilder.newJob().ofType(SampleJob.class)
.storeDurably()
.withIdentity("Qrtz_Job_Detail")
.withDescription("Invoke Sample Job service...")
.build();
}2.4. Spring JobDetailFactoryBean
Spring 的 JobDetailFactoryBean 提供了一種 Bean 風格的方式來配置 JobDetail 實例。如果未指定,它將使用 Spring Bean 名稱作為 Job 名稱。
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(SampleJob.class);
jobDetailFactory.setDescription("Invoke Sample Job service...");
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}每個作業執行都會創建一個新的 JobDetail 實例。 JobDetail 對象傳遞了作業的詳細屬性。 執行完成後,對實例的引用將被丟棄。
3. 觸發器
觸發器是安排任務的機制,即觸發器實例“觸發”任務的執行。任務與觸發器之間存在明確的分工責任。
除了任務之外,觸發器還需要一個類型,我們可以根據調度要求進行選擇。
例如,我們希望安排任務每小時執行一次,永久執行,則可以使用 Quartz 的 TriggerBuilder 或 Spring 的 SimpleTriggerFactoryBean 來實現。
3.1. Quartz 觸發器構建器</em/>
TriggerBuilder 是一個 Builder 風格的 API,用於構建 觸發器 實體。
@Bean
public Trigger trigger(JobDetail job) {
return TriggerBuilder.newTrigger().forJob(job)
.withIdentity("Qrtz_Trigger")
.withDescription("Sample trigger")
.withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
.build();
}3.2. Spring <em>SimpleTriggerFactoryBean</em>
SimpleTriggerFactoryBean 提供了一種 Bean 風格的配置 SimpleTrigger 的方式。它使用 Spring Bean 名稱作為觸發器名稱,並在未指定其他配置時,默認採用無限重複。
@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setRepeatInterval(3600000);
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
return trigger;
}4. 配置 JobStore
JobStore 提供 Job 和 Trigger 的存儲機制。它還負責維護與作業調度器相關的所有數據。API 支持內存存儲和持久化存儲。4.1. 內存式 JobStore
對於我們的示例,我們將使用內存式 RAMJobStore,它提供極快的性能以及通過 quartz.properties 簡單的配置:
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore使用 RAMJobStore 的明顯缺點是它具有易變性。所有調度信息在關機之間都會丟失。如果需要在關機後保留作業定義和調度,則可以使用持久的 JDBCJobStore。
要在 Spring 中啓用內存 JobStore,我們將設置以下屬性在我們的 application.properties 中:
spring.quartz.job-store-type=memory4.2. JDBC JobStore
有兩類 JDBCJobStore:JobStoreTX 和 JobStoreCMT。它們都執行相同的功能,即在數據庫中存儲調度信息。
它們之間的區別在於如何管理用於提交數據的事務。 JobStoreCMT 類型需要應用程序事務來存儲數據,而 JobStoreTX 類型則會啓動和管理自己的事務。
對於 JDBCJobStore,有幾個屬性需要設置。 至少,我們必須指定 JDBCJobStore 的類型、數據源和數據庫驅動程序類。 對於大多數數據庫,都有驅動程序類,但 StdJDBCDelegate 覆蓋了大多數情況。
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource設置 Spring 中的 JDBC JobStore 需要幾個步驟。首先,我們在 application.properties 中設置存儲類型:
spring.quartz.job-store-type=jdbc然後我們需要啓用自動配置,併為 Quartz 調度器提供所需的數據庫連接。<em @QuartzDataSource</em> 註解負責配置和初始化 Quartz 數據庫,從而簡化了整個過程:
@Configuration
@EnableAutoConfiguration
public class SpringQrtzScheduler {
@Bean
@QuartzDataSource
public DataSource quartzDataSource() {
return DataSourceBuilder.create().build();
}
}5. 調度器 (Scheduler)
調度器 (Scheduler) 接口是與作業調度器進行交互的主要 API。
可以通過調度器 (Scheduler) 工廠實例化調度器 (Scheduler)。 創建後,我們可以使用它註冊作業 (Job) 和觸發器 (Trigger)。 初始時,調度器 (Scheduler) 處於“待機”模式,必須調用其 start 方法 以啓動執行作業 (Job) 的線程。
5.1. Quartz StdSchedulerFactory
通過簡單地調用 StdSchedulerFactory 上的 getScheduler 方法,我們可以實例化 Scheduler,並使用配置的 JobStore 和 ThreadPool 初始化它,並返回對其 API 的訪問權限。
@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory)
throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}5.2. Spring SchedulerFactoryBean
Spring 的 SchedulerFactoryBean 提供了一種 Bean 風格的方式來配置 Scheduler,管理其在應用程序上下文中的生命週期,並將其作為 Bean 暴露,以便進行依賴注入:
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
schedulerFactory.setDataSource(quartzDataSource);
return schedulerFactory;
}5.3. 配置 SpringBeanJobFactory
SpringBeanJobFactory 提供了在創建 Job 實例時,將 scheduler 上下文、Job 數據映射和 Trigger 數據條目作為屬性注入到 Job 實例中的支持。
但是,它不支持從 Application Context 中注入 Bean 引用。 感謝 這篇博客文章,我們可以為 SpringBeanJobFactory 添加自動裝配支持。
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}6. 使用 Spring Boot Actuator 觸發 Quartz 任務
從 Spring Boot 3.5.0 版本開始,Actuator 提供了一個專門的 Quartz 端點,允許您動態地與計劃任務進行交互。該端點支持通過 RESTful 接口觸發、暫停、恢復、刪除和檢查任務等操作。
6.1. 啓用 Quartz Actuator
要啓用 Quartz Actuator,第一步是向您的項目添加 Actuator 和 Quartz 依賴項。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>一旦依賴項添加完畢,下一步是通過在 application.properties文件中添加以下配置來暴露 Quartz 端點:
management.endpoints.web.exposure.include=quartz
management.endpoint.quartz.enabled=true完成這些步驟後,Quartz 任務管理將可通過 REST 端點在 /actuator/quartz</em/> 訪問。
6.2. 手動觸發 Quartz 任務
啓用 Actuator 後,我們可以隨時手動觸發 Quartz 任務,從而繞過其已安排的執行。
為了觸發任務,Spring Boot Actuator 提供以下 REST 端點:
POST /actuator/quartz/jobs/{jobGroup}/{jobName}為了觸發名為 Qrtz_Job_Detail 的任務,在 DEFAULT 組中,我們執行以下命令:
curl -X POST "http://localhost:8080/actuator/quartz/jobs/DEFAULT/Qrtz_Job_Detail" \
-H "Content-Type: application/json" \
-d '{"state":"running"}'請求應包含一個 JSON 負載,例如 {“state”:”running”}。雖然狀態屬性目前尚不影響作業的執行,但 API 要求它正確處理請求。在成功調用後,響應將提供有關觸發的作業的信息,包括其名稱、組、實現類以及觸發時精確的時間戳:
{
"group" : "DEFAULT",
"name" : "Qrtz_Job_Detail",
"className" : "org.baeldung.springquartz.basics.scheduler.SampleJob",
"triggerTime" : "2025-05-31T10:36:36.474563900Z"
}手動觸發任務在調試時非常有用,因為它允許我們快速執行任務並觀察其行為,而無需等待其計劃執行時間。它也適用於運行諸如維護之類的臨時任務,以及需要立即執行任務的緊急情況。通過手動觸發任務,我們獲得了靈活性和控制力,可以高效地響應實時事件和系統需求。
雖然本節重點介紹觸發任務,但值得注意的是,Quartz Actuator 端點還支持其他操作,例如暫停、恢復、刪除任務以及檢索任務或組信息,從而提供了一整套用於運行時 Quartz 任務管理的 REST 端點。
7. 結論
在本文中,我們使用 Quartz API 以及 Spring 的便捷類構建了我們的第一個基本調度器。
關鍵要點是,我們只需幾行代碼就能配置一個任務,而無需使用基於 XML 的配置。
完整的示例源代碼可在 GitHub 上找到:https://github.com/eugenp/tutorials/tree/master/spring-quartz。