Quartz 是 java 的 job-scheduling framwork,可使用類似 linux 的 crontab 方式設定定時啟動某個工作。
pom.xml
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
API
quartz API 的核心是 scheduler,啟動後,Scheduler 會產生多個 worker threads,也就是利用 ThreadPool,執行 Jobs。
主要的 API interface
Scheduler
Job
JobDetail
- 定義 job instances
Trigger
決定 scheduler 的定時機制
SimpleTrigger 跟 CronTrigger 兩種
JobBuilder
- 用來產生 JobDetail instances
TriggerBuilder
- 用來產生 Trigger instances
Example
SimpleJob.java
package quartz;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
// 要實作 Job interface
public class SimpleJob implements Job {
// trigger 會透過 scheduler 的 worker 呼叫 execute 執行 job
// JobExecutionContext 可提供 runtime environment 資訊
public void execute(JobExecutionContext context) throws JobExecutionException {
// 在 產生 JobDetail 時,JobData 會透過 JobDataMap 傳進 Job
// Job 利用 JobDataMap 取得 JobData
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
System.out.println("Job says: " + jobSays + ", and val is: " + myFloatValue);
}
}
JobA.java
@DisallowConcurrentExecution
可限制 Job 不會同時被執行兩次
package quartz;
import org.quartz.*;
@DisallowConcurrentExecution
public class JobA implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
TriggerKey triggerKey= context.getTrigger().getKey();
System.out.println("job A. triggerKey="+triggerKey.getName()+", group="+triggerKey.getGroup() + ", fireTime="+context.getFireTime());
}
}
JobB.java
package quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.TriggerKey;
public class JobB implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
TriggerKey triggerKey= context.getTrigger().getKey();
System.out.println("job B. triggerKey="+triggerKey.getName()+", group="+triggerKey.getGroup() + ", fireTime="+context.getFireTime());
}
}
QuartzExample.java
package quartz;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
public static void main(String args[]) {
try {
// 透過 SchedulerFactory 產生 Scheduler
SchedulerFactory schedFact = new StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
// 使用 start 啟動,使用 shutdown 停掉這個 scheduler
// 要先將 job, trigger 綁定 scheduler 後,再啟動 scheduler
// sched.start();
// sched.shutdown();
// 產生 SimpleJob,利用 JobData 傳入資料到 Job
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("myJob", "group1")
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40).repeatForever())
.build();
///////
JobDetail jobA = JobBuilder.newJob(JobA.class)
.withIdentity("jobA", "group2")
.build();
JobDetail jobB = JobBuilder.newJob(JobB.class)
.withIdentity("jobB", "group2")
.build();
// triggerA 比 triggerB 有較高的 priority,比較早先被執行
// 每 40s 啟動一次
Trigger triggerA = TriggerBuilder.newTrigger()
.withIdentity("triggerA", "group2")
.startNow()
.withPriority(15)
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40).repeatForever())
.build();
// 每 20s 啟動一次
Trigger triggerB = TriggerBuilder.newTrigger()
.withIdentity("triggerB", "group2")
.startNow()
.withPriority(10)
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(20).repeatForever())
.build();
sched.scheduleJob(job, trigger);
sched.scheduleJob(jobA, triggerA);
sched.scheduleJob(jobB, triggerB);
sched.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
執行結果
Job says: Hello World!, and val is: 3.141
job A. triggerKey=triggerA, group=group2, fireTime=Wed Aug 28 16:16:37 CST 2024
job B. triggerKey=triggerB, group=group2, fireTime=Wed Aug 28 16:16:37 CST 2024
job B. triggerKey=triggerB, group=group2, fireTime=Wed Aug 28 16:16:57 CST 2024
Job says: Hello World!, and val is: 3.141
job A. triggerKey=triggerA, group=group2, fireTime=Wed Aug 28 16:17:17 CST 2024
job B. triggerKey=triggerB, group=group2, fireTime=Wed Aug 28 16:17:17 CST 2024
QuartzExample2.java
package quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample2 {
public static void main(String args[]) {
try {
SchedulerFactory schedFact = new StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
// 產生 SimpleJob,利用 JobData 傳入資料到 Job
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("myJob", "group1")
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40).repeatForever())
.build();
// 跟上面的 Scheduler 一樣
// 如果 worker thread 不足,job 可能不會被執行
// 當 quartz 發現有這種狀況時,會使用 .withMisfireHandlingInstructionFireNow() 這個規則
// 在 misfire 時,馬上執行一次
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionFireNow().withIntervalInSeconds(40).repeatForever())
.build();
sched.scheduleJob(job, trigger);
sched.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
QuartzExample3.java
package quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
public class QuartzExample3 {
public static void main(String args[]) {
try {
SchedulerFactory schedFact = new StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
// 產生 SimpleJob,利用 JobData 傳入資料到 Job
JobDetail jobA = JobBuilder.newJob(JobA.class)
.withIdentity("jobA", "group2")
.build();
// SimpleTrigger 可設定在某個特定時間開始
// 3 seconds 後啟動 trigger
// 同樣可加上 SimpleScheduleBuilder 定時每 40s 啟動一次
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.add(java.util.Calendar.SECOND, 3);
Date myStartTime = calendar.getTime();
SimpleTrigger trigger =
(SimpleTrigger) TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startAt(myStartTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40).repeatForever())
.build();
JobDetail jobB = JobBuilder.newJob(JobB.class)
.withIdentity("jobB", "group1")
.build();
// 透過 CronScheduleBuilder 產生 scheduler
// "0 0/1 * * * ?" 代表每分鐘執行一次
// 然後產生 CronTrigger
CronTrigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?"))
.build();
sched.scheduleJob(jobA, trigger);
sched.scheduleJob(jobB, trigger2);
sched.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
執行結果
job B. triggerKey=trigger2, group=group1, fireTime=Wed Aug 28 16:11:00 CST 2024
job A. triggerKey=trigger1, group=group1, fireTime=Wed Aug 28 16:11:00 CST 2024
job A. triggerKey=trigger1, group=group1, fireTime=Wed Aug 28 16:11:40 CST 2024
job B. triggerKey=trigger2, group=group1, fireTime=Wed Aug 28 16:12:00 CST 2024
job A. triggerKey=trigger1, group=group1, fireTime=Wed Aug 28 16:12:20 CST 2024
沒有留言:
張貼留言