1、Quartz核心概念
首先我們需要明白 Quartz 的幾個核心概念,這樣理解起 Quartz 的原理就會變得簡單了。
- Job 表示一個工作,要執行的具體內容。此接口中只有一個方法,如下:void execute(JobExecutionContext context)
- JobDetail 表示一個具體的可執行的調度程序,Job 是這個可執行程調度程序所要執行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。
- Trigger 代表一個調度參數的配置,什麼時候去調。
- Scheduler 代表一個調度容器,一個調度容器中可以註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調度了
2、具體分析
2.1 Job其實由三部分組成:
- JobDetail: 用於描述這個Job是做什麼的
- 一個實現Job接口的類:告訴Quartz具體幹什麼活的
- JobDataMap: 給 Job 提供參數用的
JobDetail jobDetail = newJob(TestJob.class)
.withIdentity("job1","group2")
.usingJobData("test","sparrow")
.build();
可以看到我們在創建JobDetail的時候,將要執行的job的類名傳給了JobDetail,所以scheduler就知道了要執行何種類型的job。每次當scheduler執行job時,在調用其execute(…)方法之前會創建該類的一個新的實例;執行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;
這種執行策略帶來的一個後果是,job必須有一個無參的構造函數(當使用默認的JobFactory時);另一個後果是,在job類中,不應該定義有狀態的數據屬性,因爲在job的多次執行中,這些屬性的值不會保留,那這個時候JobDataMap就可以幹活了,JobDataMap中可以包含不限量的(序列化的)數據對象,在job實例執行的時候,可以使用其中的數據。
JobDataMap 除了像上面使用usingJobData 方式之外,還可以
jobDetail.getJobDataMap().put("test","testOne");
2.2 常用的兩種Trigger
Trigger 就是觸發器的意思,用來指定什麼時間開始觸發,觸發多少次,每隔多久觸發一次。最常用SimpleTrigger和CronTrigger這兩種。
2.2.1、SimpleTrigger
Trigger trigger = newTrigger().withIdentity("myTrigger","group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(5)
.withRepeatCount(10))
.build();
SimpleTrigger的屬性包括:開始時間、結束時間、重複次數以及重複的間隔;上面這段代碼的意思就是從現在開始,每隔5s執行一次,一共執行10次。
重複次數,可以是0、正整數,以及常量SimpleTrigger.REPEAT_INDEFINITELY。重複的間隔,必須是0,或者long型的正數,表示毫秒。注意,如果重複間隔爲0,trigger將會以重複次數併發執行(或者以scheduler可以處理的近似併發數)。
定義開始時間,比如下方代碼:5s後開始 對應的結束使用endAt
Date startTime = DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND);
Trigger trigger1 = newTrigger().withIdentity("myTrigger","group1")
.startAt(startTime)
.build();
2.2.2、CronTrigger
使用CronTrigger最主要的就是Cron表達式,關於表達式後面會專門寫一篇博文,這裏直接放個例子了,每天上午10點42觸發
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(dailyAtHourAndMinute(10, 42))
.forJob("myJob", "group1")
.build();
或者
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 * * ?"))
.forJob("myJob", "group1")
.build();
3、Springboot整合Quartz
以上只是簡單地介紹了Quartz,好在整合過程中有個過度,更多內容可以查看Quartz相關資料
pom.xml
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
業務代碼
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
String test = jobDetail.getJobDataMap().getString("test");
System.out.println(test+new Date());
}
}
測試類:
@Test
public void testThree() throws Exception{
//創建調度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定義一個觸發器
Trigger trigger = newTrigger().withIdentity("myTrigger","group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(5)
.withRepeatCount(5))
.build();
//定義一個JobDetail
JobDetail jobDetail = newJob(TestJob.class)
.withIdentity("job1","group2")
.usingJobData("test","sparrow")
.build();
//調度加入這個job
scheduler.scheduleJob(jobDetail,trigger);
//啓動
scheduler.start();
//等待任務執行完再關閉
Thread.sleep(20000);
scheduler.shutdown(true);
}
執行結果:
擴展:實際應用
以上只是測試了一下是否可用,下面來個實際應用的例子:
先創建一個任務類,具體的業務邏輯根據實際情況來,我這裏是系統給我發送一個郵件
public class DailyMailJob implements Job {
Logger logger = LoggerFactory.getLogger(DailyMailJob.class);
@Autowired
IMailService mailService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String content = "花有重開之日,人無再少年,走好腳下的路,筆直看眼前";
mailService.sendSimpleMail("[email protected]", Constant.DAILY_SUBJECT,content);
logger.info("----------------郵件已發送----------------");
}
}
再寫個任務調度配置類 這裏只是簡單舉個例子
@Configuration
public class SchedulerConfig {
@Autowired
Scheduler scheduler;
@Bean
public void startJob() throws SchedulerException {
customJobOne(scheduler);
//啓動
scheduler.start();
}
private void customJobOne(Scheduler scheduler) throws SchedulerException {
//創建調度器
//Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定義一個觸發器
Trigger trigger = newTrigger().withIdentity("mailTriggerOne","mailGroup")
.startNow()
.withSchedule(cronSchedule("0 36 16 * * ?"))
.build();
//定義一個JobDetail
JobDetail jobDetail = newJob(DailyMailJob.class)
.withIdentity("mailJobOne","JobGroup")
.build();
//調度加入這個job
scheduler.scheduleJob(jobDetail,trigger);
}
}
結果: