| 組件 | 職責 | 關鍵實現 |
|---|---|---|
| Scheduler | 調度核心,管理觸發器與任務生命週期 | StdSchedulerFactory.getDefaultScheduler() |
| Job | 業務邏輯接口,單一方法 execute() | 實現 Job 接口或繼承 QuartzJobBean |
| JobDetail | 任務定義元數據(名稱、組、數據映射) | JobBuilder.newJob().withIdentity().build() |
| Trigger | 觸發規則:SimpleTrigger(簡單) / CronTrigger(表達式) | TriggerBuilder.newTrigger().withSchedule().build() |
| JobDataMap | 任務參數上下文,支援基本類型與序列化對象 | jobDetail.getJobDataMap().put(key, value) |
| JobStore | 持久化策略:RAMJobStore(內存) / JDBCJobStore(數據庫) | quartz.properties 配置 |
public class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext ctx) {
String name = ctx.getJobDetail().getJobDataMap().getString("name");
System.out.println("Job 執行: " + name + " @ " + new Date());
}
}
public class StandaloneDemo {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("demoJob", "group1")
.usingJobData("name", "獨立模式測試")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("demoTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
System.out.println("調度器已啟動,按 Ctrl+C 停止");
}
}
<!-- web.xml -->
<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 = MyScheduler
org.quartz.scheduler.instanceId = AUTO
# 線程池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
# 持久化到數據庫(集群必備)
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# 數據源
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?useSSL=false
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = password
org.quartz.dataSource.myDS.maxConnections = 20
# XML 任務自動加載插件
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileName = quartz_jobs.xml
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
org.quartz.plugin.jobInitializer.failOnFileNotFound = false
<?xml version="1.0" encoding="UTF-8"?>
<quartz>
<job>
<job-detail>
<name>reportJob</name>
<group>reportGroup</group>
<job-class>com.example.ReportJob</job-class>
<job-data-map>
<entry><key>templateId</key><value>TPL_001</value></entry>
</job-data-map>
</job-detail>
<trigger>
<cron>
<name>reportTrigger</name>
<group>reportGroup</group>
<job-name>reportJob</job-name>
<job-group>reportGroup</job-group>
<cron-expression>0 0 8 * * ?</cron-expression> <!-- 每天 08:00 -->
</cron>
</trigger>
</job>
</quartz>
@Configuration
public class QuartzConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(true);
factory.setStartupDelay(30); // 應用啟動 30s 後啟動調度器
// 載入 XML 任務定義
factory.setConfigLocation(new ClassPathResource("quartz_jobs.xml"));
// 集群屬性
Properties props = new Properties();
props.setProperty("org.quartz.jobStore.isClustered", "true");
factory.setQuartzProperties(props);
return factory;
}
}
@Component
public class ReportJob extends QuartzJobBean { // 支援 @Autowired 注入 Spring Bean
@Autowired private ReportService reportService;
@Override
protected void executeInternal(JobExecutionContext ctx) {
String templateId = ctx.getMergedJobDataMap().getString("templateId");
reportService.generateDailyReport(templateId);
}
}
| 字段 | 允許值 | 特殊符號 |
|---|---|---|
| 秒 | 0-59 | , - * / |
| 分 | 0-59 | , - * / |
| 時 | 0-23 | , - * / |
| 日 | 1-31 | , - * ? / L W |
| 月 | 1-12 / JAN-DEC | , - * / |
| 周 | 1-7 / SUN-SAT | , - * ? / L # |
| 年(可選) | 1970-2099 | , - * / |
常用範例:0 0 12 * * ? (每天中午12點) | 0 0/5 * * * ? (每5分鐘) | 0 0 0 ? * MON (每周一午夜)
Quartz 以 Job/Trigger/JobDetail 解耦業務與調度,CronTrigger 表達式支撐複雜時間規則,JDBCJobStore + 集群模式 保證高可用。Spring Boot 整合後,配合 @Component Job 與 SchedulerFactoryBean,即可獲得企業級定時任務平台能力:持久化、集群、動態增刪改、監控追蹤。