Quartz框架三大核心:
1:scheduler
代表一個Quartz的獨立運行容器,Trigger和JobDetail可以注冊到Scheduler中,兩者在Scheduler中擁有各自的組及名稱,組及名稱是Scheduler查找定位容器中某一對象的依據,Trigger的組及名稱必須唯一,JobDetail的組和名稱也必須唯一(但可以和Trigger的組和名稱相同,因為它們是不同類型的)。Scheduler定義了多個接口方法,允許外部通過組及名稱訪問和控制容器中Trigger和JobDetail。
Scheduler可以將Trigger綁定到某一JobDetail中,這樣當Trigger觸發時,對應的Job就被執行,例如:如schedulerTest.scheduleJob(jobTest, triggerTest)。一個Job可以對應多個Trigger,但一個Trigger只能對應一個Job。Scheduler擁有一個SchedulerContext,它類似於ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以訪問SchedulerContext內的信息。SchedulerContext內部通過一個Map,以鍵值對的方式維護這些上下文數據,SchedulerContext為保存和獲取數據提供了多個put()和getXxx()的方法。可以通過Scheduler# getContext()獲取對應的SchedulerContext實例。
scheduler 由 scheduler 工廠創建:包括DirectSchedulerFactory 和 StdSchedulerFactory(STD:standard標准的意思)。 第二種工廠 StdSchedulerFactory 使用較多,因為 DirectSchedulerFactory 使用起來不夠方便,需要作許多詳細的手工編碼設置。
scheduler 主要有三種:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。
scheduler 除了啟動外,scheduler 操作包括查詢、設置 scheduler 為 standby 模式、繼續、停止。
啟動scheduler 非常簡單,只需要調用 start() 方法即可。只有在scheduler 有實例或standby 模式才能調用start() 方法,一旦調用shutdown() 方法之后就不能再調用start() 方法。
2:trigger
在 Quartz 中,trigger 是用於定義 Job 何時執行。當用 Scheduler 注冊一個 Job 的時候要創建一個 Trigger 與這個 Job 相關聯。
Quartz 中主要提供了四種類型的 Trigger:包括SimpleTrigger、CronTirgger//DateIntervalTrigger和 NthIncludedDayTrigger。這四種 trigger 可以滿足企業應用中的絕大部分需求。
最常用的是 SimpleTrigger 和 CronTrigger 。
一般來說,如果你需要在一個固定的時間和重復次數或者一個固定的間隔時間,那么 SimpleTrigger 比較合適;
如果你有許多復雜的作業調度,那么 CronTrigger 比較合適。CronTrigger 和 Unix 的 cron 機制基本一樣,基於通用的公歷,我們需要的只是熟悉cron 表達式的用法。
關於Quartz中時間表達式的設置—–corn表達式:
withIdentity() 給觸發器一些屬性 比如名字,組名。
startNow() 立刻啟動
withSchedule(ScheduleBuilder schedBuilder) 以某種觸發器觸發。
usingJobData(String dataKey, Boolean value) 給具體job傳遞參數。
3:JobDetail & Job
jobdetail 就是對job的定義,而job是具體執行的邏輯內容。
具體的執行的邏輯需要實現 job類,並實現execute方法。
這里為什么需要有個JobDetai來作為job的定義,為什么不直接使用job?
解釋:如果使用jobdetail來定義,那么每次調度都會創建一個new job實例,這樣帶來的好處就是任務並發執行的時候,互不干擾,不會對臨界資源造成影響。
在線學習Quartz框架和API
實現簡單的demo
導入jar包
1 <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
2 <dependency>
3 <groupId>org.quartz-scheduler</groupId>
4 <artifactId>quartz</artifactId>
5 <version>1.8.6</version>
6 </dependency>
SimpleTrigger
新建任務類
1 import org.quartz.Job; 2 import org.quartz.JobExecutionContext; 3 import org.quartz.JobExecutionException; 4
5 //任務類要實現job接口以及重寫execute方法
6 public class jobDemo implements Job { 7 @Override 8 public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { 9 System.out.println("這是任務類要做的任務"); 10 } 11 }
新建觸發類(這里任務調度類也寫在一起了)
1 import org.quartz.*; 2 import org.quartz.impl.StdSchedulerFactory; 3
4 import java.util.Date; 5
6 //觸發類,觸發方法
7 public class traggerDemo { 8 public static void main(String[] args) { 9 //要構造實例化 第一個是工作名稱 第二個是任務組 第三個是任務類
10 JobDetail jobDetail=new JobDetail("工作名稱","A",jobDemo.class); 11 //創建觸發器 第一個參數是觸發器的名稱(myTrigger) 第二個參數是執行觸發的間隔(無限觸發) 第三個參數是間隔的時長(3秒)
12 SimpleTrigger simpleTrigger=new SimpleTrigger("myTrigger",SimpleTrigger.REPEAT_INDEFINITELY,3000); 13 //創建完觸發器要設置觸發器的開始時間 現在開始
14 simpleTrigger.setStartTime(new Date()); 15
16 //開始實例化調度類的調度工廠
17 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); 18 try { 19 //獲得調度核心
20 Scheduler scheduler=schedulerFactory.getScheduler(); 21 //開始整合任務類和觸發類 第一個參數是任務類 第二個參數是觸發類
22 scheduler.scheduleJob(jobDetail,simpleTrigger); 23 //執行整合並開始任務
24 scheduler.start(); 25 //休眠15秒后關閉
26 Thread.sleep(15000); 27 scheduler.shutdown(); 28 } catch (Exception e) { 29 e.printStackTrace(); 30 } 31
32 } 33 }
CronTrigger版
這是任務類
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; //還是實現並重寫
public class jobDemo implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("這是表達式觸發的例子"); } }
新建觸發類(這里任務調度類也寫在一起了)
1 import org.quartz.*; 2 import org.quartz.impl.StdSchedulerFactory; 3
4 import java.text.ParseException; 5 import java.util.Date; 6
7 public class triggerDemo { 8 public static void main(String[] args) { 9 //這是任務類,分組到B組,名字是ctg
10 JobDetail jobDetail=new JobDetail("ctg","B",jobDemo.class); 11
12 try { 13 //設置每年每月每日的14:17:00秒觸發,這是cron表達式
14 CronTrigger cronTrigger=new CronTrigger("mytrigger2","B","0 17 14 ? * * "); 15 //立刻開啟
16 cronTrigger.setStartTime(new Date()); 17
18 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); 19 Scheduler scheduler=schedulerFactory.getScheduler(); 20 scheduler.scheduleJob(jobDetail,cronTrigger); 21 scheduler.start(); 22 Thread.sleep(30000); 23 scheduler.shutdown(); 24 } catch (ParseException e) { 25 e.printStackTrace(); 26 } catch (SchedulerException e) { 27 e.printStackTrace(); 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } 31 } 32 }
spring的任務調度
整體demo結構圖

還是要帶入jar包
1 <properties>
2 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3 <maven.compiler.source>1.7</maven.compiler.source>
4 <maven.compiler.target>1.7</maven.compiler.target>
5 <!-- spring版本號 -->
6 <spring.version>4.2.5.RELEASE</spring.version>
7 </properties>
8
9 <dependencies>
10 <dependency>
11 <groupId>junit</groupId>
12 <artifactId>junit</artifactId>
13 <version>4.11</version>
14 <scope>test</scope>
15 </dependency>
16
17 <dependency>
18 <groupId>org.quartz-scheduler</groupId>
19 <artifactId>quartz</artifactId>
20 <version>1.8.6</version>
21 </dependency>
22
23 <!-- 添加spring核心依賴 -->
24 <dependency>
25 <groupId>org.springframework</groupId>
26 <artifactId>spring-core</artifactId>
27 <version>${spring.version}</version>
28 </dependency>
29
30 <dependency>
31 <groupId>org.springframework</groupId>
32 <artifactId>spring-web</artifactId>
33 <version>${spring.version}</version>
34 </dependency>
35
36 <dependency>
37 <groupId>org.springframework</groupId>
38 <artifactId>spring-oxm</artifactId>
39 <version>${spring.version}</version>
40 </dependency>
41
42 <dependency>
43 <groupId>org.springframework</groupId>
44 <artifactId>spring-tx</artifactId>
45 <version>${spring.version}</version>
46 </dependency>
47
48 <dependency>
49 <groupId>org.springframework</groupId>
50 <artifactId>spring-jdbc</artifactId>
51 <version>${spring.version}</version>
52 </dependency>
53
54 <dependency>
55 <groupId>org.springframework</groupId>
56 <artifactId>spring-webmvc</artifactId>
57 <version>${spring.version}</version>
58 </dependency>
59
60 <dependency>
61 <groupId>org.springframework</groupId>
62 <artifactId>spring-context</artifactId>
63 <version>${spring.version}</version>
64 </dependency>
65
66 <dependency>
67 <groupId>org.springframework</groupId>
68 <artifactId>spring-context-support</artifactId>
69 <version>${spring.version}</version>
70 </dependency>
71
72 <dependency>
73 <groupId>org.springframework</groupId>
74 <artifactId>spring-aop</artifactId>
75 <version>${spring.version}</version>
76 </dependency>
77
78 <dependency>
79 <groupId>org.springframework</groupId>
80 <artifactId>spring-test</artifactId>
81 <version>${spring.version}</version>
82 </dependency>
applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:context="http://www.springframework.org/schema/context"
5 xmlns:aop="http://www.springframework.org/schema/aop"
6 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
7 xsi:schemaLocation="http://www.springframework.org/schema/beans
8 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
9 http://www.springframework.org/schema/context
10 http://www.springframework.org/schema/context/spring-context-3.2.xsd
11 http://www.springframework.org/schema/aop
12 http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
13 http://www.springframework.org/schema/tx
14 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"
15 xmlns:p="http://www.springframework.org/schema/p"
16 >
17
18 <!-- Enables the Spring Task @Scheduled programming model -->
19 <!-- 開啟定時任務 -->
20 <task:annotation-driven />
21 <!--spring掃描全部包的注解加入到Spring容器內-->
22 <context:component-scan base-package="com.bdqn.text" />
23
24
25 </beans>
任務觸發調度類
1 package com.bdqn.text; 2
3 import org.springframework.scheduling.annotation.Scheduled; 4 import org.springframework.stereotype.Component; 5 //定義一個bean名叫ssaa方便后續調用
6 @Component("ssaa") 7 public class SpringCronDemo1 { 8
9 @Scheduled(cron = " * * * ? * * ") 10 public void show(){ 11 System.out.println("這是Spring的Quartz整合測試"); 12 } 13 }
測試方法
1 package com.bdqn.text; 2
3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5
6 public class Text { 7 public static void main(String[] args) { 8 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); 9 applicationContext.getBean("ssaa",SpringCronDemo1.class).show(); 10 } 11 }
項目中出現的問題:
cron表達式怎么寫?
答:這個問題,有點尷尬,本來quartz框架用起來就很簡單,重點都是在於cron表達式如何寫。所以大家還是多google,這里給個地址,我當時看的一篇專欄。
https://zhuanlan.zhihu.com/p/35629505
如何禁止並發執行?
答:項目中出現了一種情況,本來job執行時間只需要10s,但是由於數據庫量增大之后,執行時間變成了60s,而我設置的間隔時間是30s,這樣就會出現上次任務還沒執行完成,下次任務就開始執行了。所以,在這種情況下,我們要禁止quart的並發操作。
2種方式:
spring中將job的concurrent屬性設置為false。默認是true 如下:
1 <bean id="scheduleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
2 <property name="targetObject" ref="scheduleBusinessObject"/>
3 <property name="targetMethod" value="doIt"/>
4 <property name="concurrent" value="false"/>
5 </bean>
job類上加上注解@DisallowConcurrentExecution。
1 @DisallowConcurrentExecution 2 public class HelloQuartz implements Job { 3
4 @Override 5 public void execute(JobExecutionContext jobExecutionContext) { 6 JobDetail detail = jobExecutionContext.getJobDetail(); 7 String name = detail.getJobDataMap().getString("name"); 8 System.out.println("my job name is " + name + " at " + new Date()); 9
10 } 11 }
注意:@DisallowConcurrentExecution是對JobDetail實例生效,如果一個job類被不同的jobdetail引用,這樣是可以並發執行。
1 package demos; 2
3 import org.quartz.DisallowConcurrentExecution; 4 import org.quartz.Job; 5 import org.quartz.JobExecutionContext; 6 import org.quartz.JobExecutionException; 7
8 import java.text.SimpleDateFormat; 9 import java.util.Date; 10
11 /**
12 * @Description: 自定義任務 13 * @date 2021-11-11 23:13 14 */
15 @DisallowConcurrentExecution // 禁止並發執行,防止間隔時間過短,上次任務還沒執行完,下次任務就開始執行了。
16 public class HelloJob implements Job { 17 public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { 18 //打印當前的執行時間,格式為:2017-09-06 00:00:00
19 Date date = new Date(); 20 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 21 System.out.println("當前的時間為(HelloJob):" + sf.format(date)); 22 //編寫具體的業務邏輯
23 System.out.println("Hello Job!"); 24 } 25 }
1 package demos; 2
3 import org.quartz.*; 4 import org.quartz.impl.StdSchedulerFactory; 5
6 import java.text.SimpleDateFormat; 7 import java.util.Date; 8
9 /**
10 * @Description: 任務調度類 11 * @date 2021-11-11 23:16 12 */
13 public class HelloScheduler { 14 public static final String JOB_NAME = "myjob"; 15 public static final String JOB_GROUP = "group1"; 16 public static final String TRIGGER_NAME = "myTrigger"; 17 public static final String TRIGGER_GROUP = "group1"; 18
19 public static void main(String[] args) throws SchedulerException { 20 /**
21 * JobDetail:用來綁定Job,並且在job執行的時候攜帶一些執行的信息 22 */
23 //創建一個JobDetail實例,將該實例與HelloJob Class綁定
24 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity(JOB_NAME, JOB_GROUP).build(); 25 /**
26 * Trigger:用來觸發job去執行的,包括定義了什么時候去執行, 27 * 第一次執行,是否會一直重復地執行下去,執行幾次等 28 */
29 //創建一個Trigger實例,定義該job立即執行,並且每隔2秒鍾重復執行一次,直到程序停止
30 /**
31 * trigger通過builder模式來創建,TriggerBuilder.newTrigger() 32 * withIdentity():定義一個標識符,定義了組 33 * startNow():定義現在開始執行, 34 * withSchedule(SimpleScheduleBuilder.simpleSchedule():withSchedule也是builder模式創建 35 *.withIntervalInSeconds(2).repeatForever()):定義了執行頻度:每2秒鍾執行一次,不間斷地重復執行 36 * build():創建trigger 37 */
38
39 Trigger trigger = TriggerBuilder.newTrigger() 40 .withIdentity(TRIGGER_NAME,TRIGGER_GROUP).startNow() 41 .withSchedule(SimpleScheduleBuilder.simpleSchedule() 42 .withIntervalInSeconds(2).repeatForever()).build(); 43
44 //創建scheduler實例:
45 /**
46 * scheduler區別於trigger和jobDetail,是通過factory模式創建的 47 */
48 //創建一個ScheduleFactory
49 SchedulerFactory sfact = new StdSchedulerFactory(); 50 Scheduler scheduler = sfact.getScheduler(); 51 scheduler.start(); 52
53 //打印當前時間
54 Date date = new Date(); 55 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 56 System.out.println("當前的時間為(HelloScheduler):" + sf.format(date)); 57
58 //需要將jobDetail和trigger傳進去,並將jobDetail和trigger綁定在一起。
59 scheduler.scheduleJob(jobDetail,trigger); 60 } 61 }
1 package demos; 2
3 import org.quartz.*; 4 import org.quartz.impl.StdSchedulerFactory; 5
6 import java.text.SimpleDateFormat; 7 import java.util.Date; 8
9 /**
10 * @Description: 任務調度類 11 * @date 2021-11-11 23:16 12 */
13 public class HelloScheduler2 { 14 public static final String JOB_NAME = "myjob"; 15 public static final String JOB_GROUP = "group1"; 16 public static final String TRIGGER_NAME = "myTrigger"; 17 public static final String TRIGGER_GROUP = "group1"; 18
19
20 public static void main(String[] args) throws SchedulerException { 21 /**
22 * JobDetail:用來綁定Job,並且在job執行的時候攜帶一些執行的信息 23 */
24 //創建一個JobDetail實例,將該實例與HelloJob Class綁定
25 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity(JOB_NAME, JOB_GROUP).build(); 26 /**
27 * Trigger:用來觸發job去執行的,包括定義了什么時候去執行, 28 * 第一次執行,是否會一直重復地執行下去,執行幾次等 29 */
30
31 // 創建cron表達式
32 Trigger trigger = TriggerBuilder.newTrigger() 33 .withIdentity(TRIGGER_NAME,TRIGGER_GROUP).startNow() 34 .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 8-20 * * ?")).build(); // // 每天8:00-20:00,每隔1分鍾執行一次 35
36 //創建scheduler實例:
37 /**
38 * scheduler區別於trigger和jobDetail,是通過factory模式創建的 39 */
40 //創建一個ScheduleFactory
41 SchedulerFactory sfact = new StdSchedulerFactory(); 42 Scheduler scheduler = sfact.getScheduler(); 43 scheduler.start(); 44
45 //打印當前時間
46 Date date = new Date(); 47 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 48 System.out.println("當前的時間為(HelloScheduler):" + sf.format(date)); 49
50 //需要將jobDetail和trigger傳進去,並將jobDetail和trigger綁定在一起。
51 scheduler.scheduleJob(jobDetail,trigger); 52 } 53 }