Web 應用中常見需求:定時報表生成、數據同步、郵件發送、緩存刷新… 若各開發者自行實現(Thread.sleep、Timer、甚至調用系統 cron),將導致:
Quartz 是成熟、開源、純 Java 的調度框架,支持 Cron 表達式、集群、持久化、監聽器、插件化啟動,是 Web 應用調度的標準選擇。
利用 Struts PlugIn 機制,在容器啟動時初始化 Scheduler,提供統一入口 SchedulerPlugIn.scheduleWork(JobDetail, Trigger),業務代碼無需關心啟動細節。
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>false</param-value> <!-- 由插件控制啟動 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<plug-in className="com.example.SchedulerPlugIn">
<set-property property="startOnLoad" value="true" />
<set-property property="startupDelay" value="5000" /> <!-- 延遲 5 秒啟動,等待其他初始化完成 -->
</plug-in>
public class SchedulerPlugIn implements PlugIn {
private static Scheduler scheduler;
private String startOnLoad, startupDelay;
public void init(ActionServlet servlet, ModuleConfig config) {
ServletContext ctx = servlet.getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory)
ctx.getAttribute(QuartzInitializerServlet.QUARTZ_FACTORY_KEY);
try {
scheduler = factory.getScheduler();
if (Boolean.TRUE.toString().equals(startOnLoad)) {
new Thread(new DelayedSchedulerStarter(scheduler,
Long.parseLong(startupDelay)), "Delayed_Scheduler").start();
}
} catch (Exception e) { e.printStackTrace(); }
}
public static void scheduleWork(JobDetail job, Trigger trigger) {
try { scheduler.scheduleJob(job, trigger); }
catch (SchedulerException e) { e.printStackTrace(); }
}
// destroy() 中關閉 scheduler...
}
// 1. 定義觸發器:每周三 15:00
Trigger trigger = new CronTrigger("trigger1", "group1");
trigger.setCronExpression("0 0 15 ? * WED");
// 2. 定義任務詳情
JobDetail job = new JobDetail("ReportJob", "ReportGroup",
GenerateReportJob.class, true, true, true);
// 3. 一行代碼調度
SchedulerPlugIn.scheduleWork(job, trigger);
public class GenerateReportJob extends Job {
public void execute(JobExecutionContext ctx) {
JobDetail detail = ctx.getJobDetail();
String jobName = detail.getName();
JobDataMap data = detail.getJobDataMap(); // 可傳遞參數
// 業務邏輯:查詢數據、生成 PDF、發送郵件...
System.out.println("Report generated: " + jobName);
}
}
| 需求 | 代碼示例 |
|---|---|
| 每天 02:22 | TriggerUtils.makeDailyTrigger(2, 22) 或 new CronTrigger(...).setCronExpression("0 22 2 * * ?") |
| 每 5 秒 | TriggerUtils.makeSecondlyTrigger(5) 或 SimpleTrigger setRepeatInterval(5000) |
| 每 24 小時 | SimpleTrigger setRepeatInterval(24L*60*60*1000) |
| 工作日 09:00 | CronTrigger "0 0 9 ? * MON-FRI" |