Quartz
1.1 簡介
Quartz :http://www.quartz-scheduler.org/
是一個定時任務(wù)調(diào)度框架。比如你遇到這樣的問題:
- 想在30分鐘后硕淑,查看訂單是否支付弟灼,未支付則取消訂單
- 想在每月29號族跛,信用卡自動還款
- ...
- 想定時在某個時間鞍爱,去做某件事(任務(wù))初肉。
Quartz是要做定時任務(wù)的調(diào)度呻惕,設(shè)置好觸發(fā)時間規(guī)則荆责,以及相應(yīng)的任務(wù)(Job)即可。
二亚脆、Quartz使用
2.1 導(dǎo)入依賴
<dependencies>
<!--Quartz任務(wù)調(diào)度-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
2.2 定義Job
/**
* 工作類的具體實現(xiàn)做院,即需要定時執(zhí)行的“某件事”
* */
public class MyJob implements Job {
//執(zhí)行
public void execute(JobExecutionContext context) throws JobExecutionException {
//創(chuàng)建工作詳情
JobDetail jobDetail=context.getJobDetail();
//獲取工作的名稱
String jobName = jobDetail.getKey().getName();//任務(wù)名
String jobGroup = jobDetail.getKey().getGroup();//任務(wù)group
System.out.println("job執(zhí)行,job:"+jobName+" group:"+jobGroup);
System.out.println(new Date());
}
}
2.3 API測試
package com.qf;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.GregorianCalendar;
public class TestQuartz {
public static void main(String[] args) throws Exception{
//創(chuàng)建scheduler濒持,調(diào)度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定義一個Trigger,觸發(fā)條件類
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") //定義name/group
.startNow()//設(shè)置開始時間键耕,一旦加入scheduler,表示立即生效柑营,即開始計時
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2) //每隔2秒執(zhí)行一次
//.repeatForever()) //一直執(zhí)行屈雄,直到結(jié)束時間
.withRepeatCount(3))//設(shè)置執(zhí)行次數(shù)
//設(shè)置結(jié)束時間(注:月份默認(rèn)從0開始)
.endAt(new GregorianCalendar(2020,5,27,17,30,10).getTime())
.build();
//定義一個JobDetail
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("job1","group1") //定義name/group
.build();
//調(diào)度器 中加入 任務(wù)和觸發(fā)器
scheduler.scheduleJob(job, trigger);
//啟動任務(wù)調(diào)度
scheduler.start();
}
}
2.4 默認(rèn)配置
# 名為:quartz.properties,放置在classpath下官套,如果沒有此配置則按默認(rèn)配置啟動
# 指定調(diào)度器名稱酒奶,非實現(xiàn)類
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
# 指定線程池實現(xiàn)類
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 線程池線程數(shù)量
org.quartz.threadPool.threadCount = 10
# 優(yōu)先級,默認(rèn)5
org.quartz.threadPool.threadPriority = 5
# 非持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
2.5 核心類說明
Scheduler:調(diào)度器奶赔。所有的調(diào)度都是由它控制讥蟆,是Quartz的大腦,所有任務(wù)都是由它來管理
Job:任務(wù)纺阔,想定時執(zhí)行的事情(定義業(yè)務(wù)邏輯)
JobDetail:基于Job瘸彤,進(jìn)一步包裝。其中關(guān)聯(lián)一個Job笛钝,并為Job指定更詳細(xì)的屬性质况,比如標(biāo)識等
Trigger:觸發(fā)器〔C遥可以指定給某個任務(wù)结榄,指定任務(wù)的觸發(fā)機(jī)制。
三囤捻、Trigger
3.1 SimpleTrigger
以一定的時間間隔(單位是毫秒)執(zhí)行的任務(wù)臼朗。
- 指定起始和截止時間(時間段)
- 指定時間間隔、執(zhí)行次數(shù)
示例:
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1) //每秒執(zhí)行一次
.repeatForever())// 不限執(zhí)行次數(shù)
.endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime())
.build();
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(3) // 每3分鐘執(zhí)行一次
.withRepeatCount(3)) // 執(zhí)行次數(shù)不超過3次
.endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime())
.build();
3.2 CronTrigger 【重點
】
適合于更復(fù)雜的任務(wù)蝎土,它支持類型于Linux Cron的語法(并且更強(qiáng)大)视哑。
- 指定Cron表達(dá)式即可
示例:
// 每天10:00-12:00,每隔2秒鐘執(zhí)行一次
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group2")
.withSchedule(CronScheduleBuilder.cronSchedule("*/2 * 10-12 * * ?"))
.build();
3.2.1 Cron表達(dá)式組成
表達(dá)式組成:"秒 分 時 日 月 星期幾 [年]" 誊涯,其中"年" 是可選的挡毅,一般不指定。
- 如:"10 20 18 3 5 ?"代表"5月3日18點20分10秒暴构,星期幾不確定 "
位置 | 時間域 | 允許值 | 特殊值 |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分鐘 | 0-59 | , - * / |
3 | 小時 | 0-23 | , - * / |
4 | 日期 | 1-31 | , - * ? / L W |
5 | 月份 | 1-12 | , - * / |
6 | 星期 | 1-7 | , - * ? / L # |
7 | 年份(可選) | , - * / |
3.2.2 Cron表達(dá)式符號
表達(dá)式中可使用的特殊符號的含義如下
符號 | 語義 |
---|---|
星號(*) | 可用在所有字段中跪呈,表示對應(yīng)時間域的每一個時刻段磨,例如, 在分鐘字段時耗绿,表示“每分鐘” |
問號(?) | 該字符只在日期和星期字段中使用苹支,它通常指定為“不確定值” |
減號(-) | 表達(dá)一個范圍,如在小時字段中使用“10-12”误阻,則表示從10到12點债蜜,即10,11,12 |
逗號(,) | 表達(dá)一個列表值,如在星期字段中使用“MON,WED,FRI”堕绩,則表示星期一策幼,星期三和星期五 |
斜杠(/) | x/y表達(dá)一個等步長序列,x為起始值奴紧,y為增量步長值特姐。如在分鐘字段中使用0/15,則表示為0,15,30和45秒黍氮,而5/15在分鐘字段 中表示5,20,35,50 |
井號(#) | 該字符只用在星期字段中唐含,"4#2"代表第二個星期3,“5#4”代表第4個星期四 |
L | 該字符只在日期和星期字段中使用沫浆,代表“Last”的意思捷枯,但它在兩個字段中意思不同。 |
如果L用在星期字段里专执,則表示星期六淮捆,等同于7 | |
L出現(xiàn)在星期字段里,而且在前面有一個數(shù)值x本股,則表示“這個月的最后一個周x”攀痊,例如,6L表示該月的最后星期五 | |
L在日期字段中拄显,表示這個月份的最后一天苟径,如一月的31號,非閏年二月的28號 | |
W | 該字符只能出現(xiàn)在日期字段里躬审,是對前導(dǎo)日期的修飾棘街,表示離該日期最近的工作日 |
例如15W表示離該月15號最近的工作日,如果該月15號是星期六承边,則匹配14號星期五遭殉;如果15日是星期日,則匹配16號星期一炒刁;如果15號 是星期二恩沽,那結(jié)果就是15號星期二;但必須注意關(guān)聯(lián)的匹配日期不能夠跨月 | |
LW組合 | 在日期字段可以組合使用LW翔始,它的意思是當(dāng)月的最后一個工作日 |
3.2.3 Cron表達(dá)式示例
演示實例
表示式 | 說明 |
---|---|
0 0 12 * * ? | 每天12點運行 |
0 15 10 * * ? | 每天10:15運行 |
0 15 10 * * ? 2008 | 在2008年的每天10:15運行 |
0 * 14 * * ? | 每天14點到15點之間每分鐘運行一次罗心,開始于14:00,結(jié)束于14:59城瞎。 |
0 0/5 14 * * ? | 每天14點到15點每5分鐘運行一次渤闷,開始于14:00,結(jié)束于14:55脖镀。 |
0 0/5 14,18 * * ? | 每天14點到15點每5分鐘運行一次飒箭,此外每天18點到19點每5鐘也運行一次。 |
0 0-5 14 * * ? | 每天14:00點到14:05蜒灰,每分鐘運行一次弦蹂。 |
0 0-5/2 14 * * ? | 每天14:00點到14:05,每2分鐘運行一次强窖。 |
0 10,44 14 ? 3 4 | 3月每周三的14:10分和14:44分凸椿,各運行一次。 |
0 15 10 ? * 2-6 | 每周一翅溺,二脑漫,三,四咙崎,五的10:15分運行一次优幸。 |
0 15 10 15 * ? | 每月15日10:15分運行。 |
0 15 10 L * ? | 每月最后一天10:15分運行褪猛。 |
0 15 10 ? * 6L | 每月最后一個星期五10:15分運行网杆。【此時天必須是"?"】 |
0 15 10 ? * 6L 2007-2009 | 在2007,2008,2009年每個月的最后一個星期五的10:15分運行伊滋。 |
四碳却、Spring整合Quartz 【重點
】
4.1 依賴
<dependencies>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
4.2 定義Job
定義一個Job類
public class MyJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.err.println("job 執(zhí)行"+new Date());
}
}
4.3 配置applicationContext.xml
調(diào)度器 SchedulerFactoryBean
觸發(fā)器 CronTriggerFactoryBean
JobDetail JobDetailFactoryBean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Spring整合Quartz進(jìn)行配置遵循下面的步驟:
1:定義工作任務(wù)的Job
2:定義觸發(fā)器Trigger,并將觸發(fā)器與工作任務(wù)綁定
3:定義調(diào)度器新啼,并將Trigger注冊到Scheduler
-->
<!-- 1:定義任務(wù)的bean 追城,這里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置類似-->
<bean name="lxJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 指定job的名稱 -->
<property name="name" value="job1"/>
<!-- 指定job的分組 -->
<property name="group" value="job_group1"/>
<!-- 指定具體的job類 -->
<property name="jobClass" value="com.qf.quartz.MyJob"/>
</bean>
<!-- 2:定義觸發(fā)器的bean燥撞,定義一個Cron的Trigger座柱,一個觸發(fā)器只能和一個任務(wù)進(jìn)行綁定 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 指定Trigger的名稱 -->
<property name="name" value="trigger1"/>
<!-- 指定Trigger的名稱 -->
<property name="group" value="trigger_group1"/>
<!-- 指定Tirgger綁定的JobDetail -->
<property name="jobDetail" ref="lxJob"/>
<!-- 指定Cron 的表達(dá)式 ,當(dāng)前是每隔5s運行一次 -->
<property name="cronExpression" value="*/5 * * * * ?" />
</bean>
<!-- 3.定義調(diào)度器物舒,并將Trigger注冊到調(diào)度器中 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
<!-- 添加 quartz 配置色洞,如下兩種方式均可 -->
<!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
<property name="quartzProperties">
<value>
# 指定調(diào)度器名稱,實際類型為:QuartzScheduler
org.quartz.scheduler.instanceName = MyScheduler
# 指定連接池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 連接池線程數(shù)量
org.quartz.threadPool.threadCount = 11
# 優(yōu)先級
org.quartz.threadPool.threadPriority = 5
# 不持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
</value>
</property>
</bean>
</beans>
4.4 操作
4.4.1 啟動任務(wù)
工廠啟動冠胯,調(diào)度器啟動火诸,任務(wù)調(diào)度開始
public static void main(String[] args) throws InterruptedException, SchedulerException {
// 工廠啟動,任務(wù)啟動荠察,工廠關(guān)閉置蜀,任務(wù)停止
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
4.4.2 任務(wù)操作
4.4.2.1 刪除任務(wù)
public static void main(String[] args) throws InterruptedException, SchedulerException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("=============");
StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
System.out.println(scheduler.getClass());
Thread.sleep(3000);
// 刪除Job
scheduler.deleteJob(JobKey.jobKey("job1","job_group1"));
}
4.4.2.2 暫停奈搜、恢復(fù)
public static void main(String[] args) throws InterruptedException, SchedulerException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("=============");
StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
System.out.println(scheduler.getClass());
Thread.sleep(3000);
// 暫停,恢復(fù)工作
scheduler.pauseJob(JobKey.jobKey("job1","job_group1"));// 暫停工作
Thread.sleep(3000);
scheduler.resumeJob(JobKey.jobKey("job1","job_group1"));// 恢復(fù)工作
}
4.4.2.3 批量操作
public static void main(String[] args) throws InterruptedException, SchedulerException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("=============");
StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
System.out.println(scheduler.getClass());
Thread.sleep(3000);
GroupMatcher<JobKey> group1 = GroupMatcher.groupEquals("job_group1");
scheduler.pauseJobs(group1); // 暫停組中所有工作
Thread.sleep(2000);
scheduler.resumeJobs(group1); // 恢復(fù)組中所有工作
}