一、Quartz簡介
二、Quartz使用
三、Trigger(重 點)
四、Job並發(重點)
五、Spring整合Quartz (重點)
六、持久化
七、springboot整合 自帶的quartz
版本:
Quartz 2.2.3
官網鏈接
一、Quartz簡介
1.1、簡介
Quartz是一個任務調度框架。比如你遇到這樣的問題
想每月29號,信用卡自動還款
想每年4月1日自己給當年暗戀女神發一封匿名賀卡
想每隔1小時,備份一下自己的學習筆記
這些問題總結起來就是:在某一個有規律的時間點干某件事。並且時間的觸發的條件可以非常復雜(比如每月最后一個工作日的17:50),復雜到需要一個專門的框架來干這個事。
Quartz就是來干這樣的事,你給它一個觸發條件的定義,它負責到了時間點,觸發相應的Job起來干活
如果應用程序需要在給定時間執行任務,或者如果系統有連續維護作業,那么Quartz是理想的解決方案。
1.2、特點
1.2.1、作業調度
作業被安排在-個給定的觸發時運行。觸發器可以使用以下指令的組合來創建:
在一天中的某個時間(到毫秒)
在一周的某幾天
在每月的某一天
在一年中的某些日期
不在注冊的日歷中列出的特定日期(如商業節假日除外)
重復特定次數
重復進行,直到一個特定的時間/日期
無限重復
重復的延遲時間間隔
1.2.2、作業持久性
Quartz的設計包括一個作業存儲接口,有多種實現。
通過使用包含的JDBCJobStore,所有的作業和觸發器配置為“非揮發性"都存儲在通過JDBC關系數據庫。
通過使用包含的RAMJobStore,所有的作業和觸發器存儲在RAM,因此不計划執行仍然存在 - 但這是無需使用外部數據庫的優勢。
二、Quartz使用
2.1、導入依賴
<!--Quartz任務調度-->
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
2.2、定義Job
@DisallowConcurrentExecution
public class MyJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//創建工作詳情
JobDetail jobDetail=context.getJobDetail();
//獲取工作的名稱
String name = jobDetail.getKey().getName();//任務名
String group = jobDetail.getKey().getGroup();//任務group
String job=jobDetail.getJobDataMap().getString("data04");//任務中的數據
System.out.println("job執行,job名:"+name+" group:"+group+new Date()+job);//這里是我們最終要定時的任務
}
}
2.3、API測試
package com.xibei.test;
import com.xibei.job.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.DateBuilder.*;
public class TestQuartz {
public static void main(String[] args) throws SchedulerException, InterruptedException {
testSimpleTrigger();
}
public static void testSimpleTrigger() throws SchedulerException, InterruptedException {
// 1. 創建scheduler,調度器 核心組件
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2. 定義一個Trigger,創建觸發器:Trigger
/*Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") //定義觸發器name/group
.startNow()//一旦加入scheduler,立即生效,即開始時間
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)//每隔2秒執行一次
.withRepeatCount(2))//一共執行幾次
.build();*/
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") //定義name/group
.startNow()//一旦加入scheduler,立即生效,即開始時間
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())//一直執行下去
//.endAt(new GregorianCalendar(2019,9,19,9,59,10).getTime())//設置最終停止時間
.build();
// 3. 創建JobDetail,JobBuilder(任務)
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("job04", "group04")//任務的名字和組
.usingJobData("data04", "hello world~~")//任務中的數據和值
.build();
// 4. 注冊 JobDetail 和 Trigger
scheduler.scheduleJob(jobDetail, trigger);//將任務和觸發器注冊到調度器
// 5. 啟動調度器, 內部注冊的所有觸發器開始計時
scheduler.start();
// 6.關閉調度器
Thread.sleep(10000);//用線程睡眠來操作調度器運行的時間
scheduler.shutdown();
}
}
2.4、配置
# 指定調度器名稱,非實現類
org.quartz.scheduler.instanceName = DefaultQuartzScheduler04
# 指定線程池實現類
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 線程池線程數量
org.quartz.threadPool.threadCount = 15
# 優先級,默認5
org.quartz.threadPool.threadPriority = 5
# 非持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
2.5、核心類說明
Scheduler:調度器。所有的調度都是由它控制
Scheduler就是Quartz的大腦,所有任務都是由它來設施
Schduelr包含一個兩個重要組件: JobStore和ThreadPool
JobStore是會來存儲運行時信息的,包括Trigger ,Schduler , JobDetail,業務鎖等
ThreadPool就是線程池,Quartz有 自己的線程池實現。所有任務的都會由線程池執行
SchdulerFactory,顧名思義就是來用創建Schduler了,有兩個實現: DirectSchedulerFactory和StdSchdulerFactory。 前者可以用來在代碼里定制你自己的Schduler參數。后者是直接讀取classpath下的quartz .properties (不存 在就都使用默認值)配置來實例化Schduler。通常來講,我們使用StdSchdulerF actory也就足夠了。
SchdulerFactory本身是支持創建RMI stub的, 可以用來管理遠程的Scheduler,功能與本地一樣
三、Trigger(重點)
3.1 、SimpleTrigger
指定從某一個時間開始,以一定的時間間隔(單位是毫秒)執行的任務。
它適合的任務類似於: 9:00開始,每隔1小時,執行一次。
它的屬性有:
repeatInterval重復間隔
repeatCount重復次數。實際執行次數是repeatCount+1。 因為在startTime的時候一定會執行一次。
示例:
SimpleScheduleBuilder.simpleSchedule().
withIntervalInSeconds(10).//每隔10秒執行-次
repeatForever().//永遠執行
build();
SimpleScheduleBuilder.simpleSchedule().
withIntervalInMinutes(3).//每隔3分鍾執行一-次
withRepeatCount(3).//執行3次
build();
3.2、CalendarlntervalTrigger
類似於SimpleTrigger,指定從某一個時間開始, 以一定的時間間隔執行的任務。但是不同的是SimpleT rigger指定的時間間隔為毫秒,沒辦法指定每隔一個月執行一次(每月的時間間隔不是固定值), 而CalendarIntervalTrigger支持的間隔單 位有秒,分鍾,小時,天,月,年,星期。
示例:
CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInDays(2) //每2天執行一次
.build();
CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInWeeks(1) //每周執行一次
.build();
3.3、DailyTimelntervalTrigger
指定每天的某個時間段內,以一定的時間間隔執行任務。並且它可以支持指定星期。
它適合的任務類似於:指定每天9:00至18:00 ,每隔70秒執行一次,並且只要周一至周五執行。
它的屬性有:
startTime0fDay每天開始時間
endTime0fDay每天結束時間
daysOfWeek需要執行的星期
interval執行間隔
intervalUnit執行間隔的單位(秒, 分鍾,小時,天,月,年,星期)
repeatCount重復次數
示例:
DailyTimeIntervalScheduleBuilder.dailyTime IntervalSchedule()
.start ingDailyAt (TimeOfDay.hourAndMinute0fDay(9, 0)) //每天9:00開始
.endingDailyAt (TimeOfDay.hour AndMinute0fDay(18, 0)) //18:00結束
.onDaysOfTheWeek( MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五執行
.withIntervalInHours(1) //每間隔1小時執行一次
.withRepeatCount(100) //最多重復100次(實際執行100+1次)
.build();
DailyTimeIntervalScheduleBuilder.dailyTime IntervalSchedule()
.start ingDailyAt(Time0fDay.hourAndMinuteOfDay(10,0)) //每天10:00開始
.endingDailyAfterCount(10)//每天執行10次, 這個方法實際上根據startTimeOfDaytinterval*count算出endTimeOfDay
.onDaysOfTheWeek(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY)//周一至周五執行
.withIntervalInHours(1)//每間隔1小時執行一次
.build();
3.4 CronTrigger (重點)
適合於更復雜的任務,它支持類型於Linux Cron的語法(並且更強大)。基本上它覆蓋了以上三個Trigger的絕大部分能力(但不是全部) -- 當然,也更難理解。
它適合的任務類似於:每天0:00,9:00,18:00各執行-次。
它的屬性只有:
Cron表達式。但這個表示式本身就夠復雜了
示例:
CronScheduleBuilder.cronSchedule("0 0/2 10-12 * * ?") //每天10:00-12:00, 每隔2分鍾執行一次
.build();
cronSchedule("0 30 9 ? * MON") //每周一,9:30執行一次
.build();
CronScheduleBuilder.week1yOnDayAndHourAndMinute(MONDAY,9,30) //等同於 0 30 9 ? * MON
. build();
3.4.1、Cron表達式
[1] [2] [3] ? [5] 3#5
星號(*): 可用在所有字段中,表示對應時間域的每一個時刻,例如,在分鍾字段時, 表示“每分鍾”;
問號(?): 該字符只在日期和星期字段中使用,它通常指定為“不確定值”
減號(-): 表達一一個范圍,如在小時字段中使用“10-12",則表示從10到12點,即10, 11,12;
逗號(,): 表達一個列表值,如在星期字段中使用“MON, WED, FRI",則表示星期一,星期三和星期五;
斜杠(/): x/y表達一個等步長序列, x為起始值,y為增量步長值。如在分鍾字段中使用0/15,則表示為日,15,30和45秒,而5/15在分鍾字段中表示5, 20, 35, 50,你也可以使用*/y,它等同於0/y;
L: 該字符只在日期和星期字段中使用,代表"Last"的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最后一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同於7。但是,如果L出現在星期字段里,而且在前面有-個數值X,則表示"這個月的最后一個周x",例如,6L表示該月的最后星期五;
W: 該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如1 5W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍;
LW組合: 在日期字段可以組合使用LW,它的意思是當月的最后一個工作日;
表達式示例:
Calendar不是jdk的java.util.Calendar,不是為了計算日期的。它的作用是在於補充Trigger的時間。可以排除或加入某一些特定的時間點。
以”每月29日零點自動還信用卡“為例,我們想排除掉每年的2月29號零點這個時間點(因為平年和潤年2月不一樣)。這個時間,就可以用Calendar來實現。
Quartz提供以下幾種Calendar,注意,所有的Calendar既可以是排除, 也可以是包含,取決於:
HolidayCalendar。指定特定的日期,比如20140613。 精度到天。
DailyCalendar.指定每天的時間段(rangeStartingTime, rangeEndingTime),格式是HH:M:SS[:mmm]]。 也就是最大精度可以到毫秒。
WeeklyCalendar。指定每星期的星期幾,可選值比如為java.util.Calendar.SUNDAY.精度是天。
MonthlyCalendar。指定每月的幾號。可選值為1-31。精度是天
AnnualCalendar。指定每年的哪一天。使用方式如上例。精度是天。
CronCalendar。指定Cron表達式。精度取決於Cron表達式,也就是最大精度可以到秒。
當scheduler比較繁忙的時候,可能在同一個時刻,有多個Trigger被觸發了,但資源不足(比如線程池不足)。那么這個時候比剪刀石頭布更好的方式,就是設置優先級。優先級高的先執行。
需要注意的是,優先級只有在同一時刻執行的Trigger之間才會起作用,如果一個Trigger是9:00, 另-個Trigger是9:30。那么無論后一個優先級多高, 前一個都是先執行。
優先級的值默認是5,當為負數時使用默認值。最大值似乎沒有指定,但建議遵循Java的標准,使用1-10,不然鬼才知道看到[優先級為10]是時,上頭 還有沒有更大的值。
四、Job並發(重點)
job是有可能並發執行的,比如一個任務要執行10秒中,而調度算法是每秒中觸發1次,那么就有可能多個任務被並發執行。
有時候我們並不想任務並發執行,比如這個任務要去"獲得數據庫中所有未發送郵件的名單”,如果是並發執行,就需要一個數據庫 鎖去避免一個數據被多次處理。這個時候一個@DisallowConcurrentExecution解決這個問題
@DisallowConcur rentExecution
public class DoNothingJob implements Job {
public void execute (JobExecutionContext context) throws JobExecut ionE xception {
System.out.println( "操作"):
}
}
注意,@DisallowConcurrentExecution是對 JobDetail實例生效,也就是如果你定義兩個JobDetail,引用同一個Job類,是可以並發執行的
代碼示例:
@DisallowConcurrentExecution //會不允許並發執行,(如果每1s觸發 -次,但每個j ob要執行3秒)
public class MyJob implements Job{
@Override
public void execute (JobExecutionContext context) throws JobExecutionException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e. printStackTrace();
}
System.out.println("任務調度:組:"+group+",工作名:" +name+" "+data+new Date());
}
}
五、Spring整合Quartz (重點)
5.1、依賴
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<springframework.version>4.3.6.RELEASE</springframework.version>
<quartz.version>2.2.3</quartz.version>
<druid>1.1.12</druid>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Quartz任務調度-->
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
<!-- druid依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid}</version>
</dependency>
<!-- mysql驅動 依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
<scope>runtime</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
5.2、配置
調度器 SchedulerFactoryBean
觸發器 CronTriggerFactoryBean
JobDetail JobDetailFactoryBean
1、applicationContext_quartz.xml
<?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進行配置遵循下面的步驟:
1:定義工作任務的Job
2:定義觸發器Trigger,並將觸發器與工作任務綁定
3:定義調度器,並將Trigger注冊到Scheduler
-->
<!-- 1:定義任務的bean ,這里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置類似-->
<bean name="lxJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 指定job的名稱 -->
<property name="name" value="job1"/>
<!-- 指定job的分組 -->
<property name="group" value="group1"/>
<!-- 指定具體的job類 -->
<property name="jobClass" value="com.xibei.job.MyJob"/>
<!-- 如果為false,當沒有活動的觸發器與之關聯時會在調度器中會刪除該任務 (可選) -->
<property name="durability" value="true"/>
<!-- (可選)
指定spring容器的key,如果不設定在job中的jobmap中是獲取不到spring容器的
其實現了ApplicationContextWare,則其中的setApplicationContext方法會得到
當前的工廠對象,且將工廠對象存在了類中的一個屬性“applicationContext”中,源碼如下
getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
則在Job的jobmap中可以獲得工廠對象,如果需要可以使用
(ApplicationContext) jobDataMap.get("applicationContext04");
jobDataMap.get("data04");
.usingJobData("data04", "hello world~~")
.usingJobData("applicationContext04",spring工廠對象)
-->
<!--<property name="applicationContextJobDataKey" value="applicationContext04"/>-->
</bean>
<!-- 2.2:定義觸發器的bean,定義一個Cron的Trigger,一個觸發器只能和一個任務進行綁定 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 指定Trigger的名稱 -->
<property name="name" value="hw_trigger"/>
<!-- 指定Trigger的名稱 -->
<property name="group" value="hw_trigger_group"/>
<!-- 指定Tirgger綁定的Job -->
<property name="jobDetail" ref="lxJob"/>
<!-- 指定Cron 的表達式 ,當前是每隔5s運行一次 -->
<property name="cronExpression" value="* * * * * ?" />
</bean>
<!-- 3.定義調度器,並將Trigger注冊到調度器中 -->
<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>
# 指定調度器名稱,實際類型為:QuartzScheduler
org.quartz.scheduler.instanceName = MyScheduler
# 指定連接池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 連接池線程數量
org.quartz.threadPool.threadCount = 11
# 優先級
org.quartz.threadPool.threadPriority = 5
# 不持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
</value>
</property>
</bean>
</beans>
web.xml項目的全局配置
5.3、代碼
MyJob自定義任務類
TestQuartzSpring
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_quartz.xml")
public class TestQuartzSpring {
@Autowired
private StdScheduler scheduler;
@Test
public void test1() throws InterruptedException, SchedulerException {
System.out.println("hello");
Thread.sleep(5000);
// 刪除 job
/*scheduler.pauseTrigger(TriggerKey.triggerKey("hw_trigger","hw_trigger_group"));//暫停觸發器的計時
scheduler.unscheduleJob(TriggerKey.triggerKey("hw_trigger", "hw_trigger_group"));// 移除觸發器中的任務
scheduler.deleteJob(JobKey.jobKey("job1","group1"));//移除trigger后,刪除工作*/
// job 暫停 和 恢復
/* scheduler.pauseJob(JobKey.jobKey("job1","group1"));
Thread.sleep(30000);
scheduler.resumeJob(JobKey.jobKey("job1","group1"));*/
GroupMatcher<JobKey> groups = GroupMatcher.groupEquals("group1");//名字等於group1
scheduler.pauseJobs(groups);// 暫停組內所有的job
Thread.sleep(5000);
scheduler.resumeJobs(groups);
Thread.sleep(5000);
}
}
六、持久化
6.1、建表
quartz官方提供了完整的持久化job的支持,並給出了一套庫表
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;
6.2、配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定義調度器,並將Trigger注冊到調度器中 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 添加 quartz 配置,如下兩種方式均可 -->
<!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
<property name="quartzProperties">
<value>
# 指定調度器名稱,實際類型為:QuartzScheduler
org.quartz.scheduler.instanceName = MyScheduler
# 指定連接池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 連接池線程數量
org.quartz.threadPool.threadCount = 11
# 優先級
org.quartz.threadPool.threadPriority = 5
# 不持久化job
# org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#quartz表的前綴
org.quartz.jobStore.tablePrefix = QRTZ_
</value>
</property>
<property name="dataSource" ref="druid"/>
</bean>
<!-- 導入外部參數文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 連接池:druid -->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close">
<!-- 基本屬性 url、user、password -->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="${jdbc.maxPoolSize}"/>
<!-- 配置獲取連接等待超時的時間 -->
<property name="maxWait" value="3000"/>
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一個連接在池中最小空閑的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="validationQuery" value="SELECT 'x'"/>
<property name="testWhileIdle" value="true"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
</bean>
</beans>
mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 告知springmvc 哪些包中 存在 被注解的類
use-default-filters="false" 遇到到 @Controller @Service @Repository @Component類,都會忽略
-->
<context:component-scan base-package="com.xibei" use-default-filters="false">
<!-- 只掃描 有@Controller注解的類 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 注冊注解開發驅動 -->
<mvc:annotation-driven/>
<!-- 視圖解析器
作用:1.捕獲后端控制器的返回值="index"
2.解析: 在返回值的前后 拼接 ==> "/index.jsp"
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前綴 -->
<property name="prefix" value="/"></property>
<!-- 后綴 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 在項目中 自動添加一個 映射{"/**" : DefaultServletHttpRequestHandler}
請求進入前端后,會先匹配自定義的Handler,如果沒有匹配的則進入DefaultServletHttpRequestHandler。
DefaultServletHttpRequestHandler會將請求轉發給Tomcat中名為"default"的servlet。
最終實現了靜態資源的訪問
-->
<mvc:default-servlet-handler/>
</beans>
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Post請求中文參數亂碼解決 -->
<filter>
<filter-name>encode</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext_quartz2.xml</param-value>
</context-param>
</web-app>
6.3、增加任務
定義一個springMVC的Handler
JobAndTrigger
public class JobAndTrigger {
private String jobName;
private String jobGroup;
private String jobClassName;
private String triggerName;
private String triggerGroup;
private BigInteger repeatInterval;
private BigInteger timesTriggered;
private String cronExpression;
private String timeZoneId;
}
QuartzController
@Controller
@RequestMapping("/quartz")
public class QuartzController {
@Autowired //注入了工廠中 調度器
private Scheduler scheduler;
@RequestMapping("/add")
public String addJob(JobAndTrigger jt) throws ClassNotFoundException, SchedulerException {
// 創建JobDetail
JobDetail jobDetail=null;
jobDetail = JobBuilder.newJob((Class<? extends Job>)Class.forName(jt.getJobClassName()))
.withIdentity(jt.getJobName(), jt.getJobGroup()).storeDurably(true).build();
CronTrigger cronTrigger = null;
cronTrigger = TriggerBuilder.newTrigger().withIdentity(jt.getJobName(),jt.getJobGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(jt.getCronExpression()))
.build();
scheduler.scheduleJob(jobDetail,cronTrigger);
return "index";
}
}
addjob.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/quartz/add" method="post">
jobName: <input type="text" name="jobName"> <br>
jobGroup: <input type="text" name="jobGroup"> <br>
cronExp: <input type="text" name="cronExpression"> <br>
jobClass: <input type="text" name="jobClassName"> <br>
<input type="submit" value="增加">
</form>
</body>
</html>
啟動Tomcat測試
七、springboot整合自帶的quartz
7.1、簡單任務
1、SimpleJob
@Configuration
public class SimpleJob {
@Scheduled(cron = "0/1 * * * * ?")
public void run() {
//任務
System.err.println(LocalDateTime.now()+"我是簡單的");//輸出紅色
}
2、SpringbootQuartzApplication
@EnableScheduling//開啟任務調度支持
@SpringBootApplication
public class SpringbootQuartzApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootQuartzApplication.class, args);
}
}
7.2、復雜任務
1、pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、連接Oracle數據庫
數據表
cron_id | cron |
---|---|
1 | 0/1 * * * * ? |
2 | 0/5 * * * * ? |
查詢語句
select "cron" from "cron" where "cron_id"=1
application.properties
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url= jdbc:oracle:thin:@localhost:1521:MLDN
spring.datasource.password=zhu
spring.datasource.username=zhu
3、ComplexJob
@Configuration
public class ComplexJob implements SchedulingConfigurer {
@Mapper
public interface CronMapper {
@Select("select \"cron\" from \"cron\" where \"cron_id\"=1")
String getCron();//返回查詢結果
}
//將cronMapper注入給ComplexJob
@Autowired
CronMapper cronMapper;
//任務,觸發器
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(
() -> System.out.println(LocalDateTime.now()+"我是復雜的"),//任務
triggerContext -> {
String cron = cronMapper.getCron();
return new CronTrigger(cron).nextExecutionTime(triggerContext);//觸發器
});
/*scheduledTaskRegistrar.addTriggerTask(new Runnable() { //任務
@Override
public void run() {
System.out.println(LocalDateTime.now()+"我是復雜的");
}
}, new Trigger() {//觸發器
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
String cron = cronMapper.getCron();
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
});*/
}
}
4、SpringbootQuartzApplication
@EnableScheduling//開啟任務調度支持
@SpringBootApplication
public class SpringbootQuartzApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootQuartzApplication.class, args);
}
}
5、測試
調度器作用:調度安排一些工作,
觸發器作用:每個任務在某個時間觸發執行,觸發誰
一個job 對應一個觸發器
jobDetail封裝了job
調度器啟動起來,啟動調度器中所有觸發器+任務(job)