Quartz

Quartz

一、Quartz簡介

Quartz官網(wǎng):http://www.quartz-scheduler.org/

是一個定時任務調(diào)度框架。可以用來處理這樣的問題:

  • 想在30分鐘后,查看訂單是否支付,未支付則取消訂單
  • 想在每個月29號信用卡自動還款
  • ......
  • 想定時在某個時間,去做某件事(執(zhí)行某個任務)

Quartz是要做定時任務的調(diào)度,設置好觸發(fā)時間規(guī)則,以及相應的任務(Job)即可。

二、Quartz的使用

2.1 核心類的說明

Scheduler:調(diào)度器。所有的調(diào)度都是由它來控制,是Quartz的大腦,所有任務都是由它來管理。

Job:任務。想定時執(zhí)行的事情(定義業(yè)務邏輯)。

JobDetail:基于Job,進一步包裝。其中關聯(lián)一個Job,并為Job指定更詳細的屬性,比如標識等。

Trigger:觸發(fā)器。可以指定給某個任務,指定任務的觸發(fā)機制。

2.2 Quartz的實現(xiàn)

Step1:導入依賴

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>

Step2:定義Job

/**
* 工作類的具體實現(xiàn), 即需要定時執(zhí)行的"某件事"
*/
public class HelloQuartzJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Job 定時執(zhí)行中 ..." + new Date());  // 打印時間, 方便觀察時間間隔
        // 可以從context中獲取JobDetail, 從而得到JobDetail的name和group
        JobDetail jobDetail = context.getJobDetail();
        JobKey key = jobDetail.getKey();
        System.out.println(key.getName());
        System.out.println(key.getGroup());
    }
}

Step3:創(chuàng)建調(diào)度器和觸發(fā)器,將Job包裝為JobDetail來實現(xiàn)任務的定時調(diào)度

public class HelloQuartz {
    @Test
    public void testQuartz() throws Exception{
        // 1. 創(chuàng)建調(diào)度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        
        // 2. 創(chuàng)建觸發(fā)器, 指定定時規(guī)則
        // 定義觸發(fā)器的name和所屬的group
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                                // 計時起始時間(startNow表示程序一啟動就開始計時)
                                .startNow()       
                                // 執(zhí)行Job的規(guī)則. 當前定義為2秒執(zhí)行1次, repeatForever表示一直執(zhí)行到計時結束, 也可以用withRepeatCount(10), 表示到計時結束之前最多執(zhí)行10次
                                .withSchedule(
                                    SimpleScheduleBuilder
                                    .simpleSchedule()
                                    .withIntervalInSeconds(2)
                                    .repeatForever())
                                // 定義計時結束時間(年, 月, 日, 時, 分, 秒)
                                .endAt(new GregorianCalendar(2020, 11, 9, 22, 07, 30).getTime())
                                .build();
        
        // 3. 包裝Job為JobDetail, 并定義JobDetail的name和所屬的group(注意: JobDetail的group不是觸發(fā)器的group, 兩者是相互隔離的, 即使group的名字相同)
        JobDetail jobDetail = JobBuilder.newJob(HelloQuartzJob.class).withIdentity("job1", "group1").build();
        
        // 4. 將JobDetail和觸發(fā)器注冊到調(diào)度器中
        scheduler.scheduleJob(jobDetail, trigger);
        
        // 5. 啟動, 調(diào)度器開始工作
        scheduler.start();
    }
}

2.3 Quartz的配置文件

名為quartz.properties,一般放置在 main/resources 下,如果沒有此配置文件則按默認配置啟動

# 指定調(diào)度器名稱, 非實現(xiàn)類
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
# 指定Quartz所用的線程池實現(xiàn)類
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 指定線程池線程的數(shù)量
org.quartz.threadPool.threadCount = 10
# 線程優(yōu)先級
org.quartz.threadPool.threadPriority = 5
# 非持久化job(即任務都放到了內(nèi)存中)
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

三、觸發(fā)器Trigger

3.1 SimpleTrigger

以一定的時間間隔執(zhí)行任務

  • 指定計時起始時間、截止時間
  • 指定時間間隔、執(zhí)行次數(shù)

示例:

 // 定義觸發(fā)器的name和所屬的group
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
// 計時起始時間(startNow表示程序一啟動就開始計時)
.startNow()       
// 執(zhí)行Job的規(guī)則. 當前定義為2秒執(zhí)行1次, repeatForever表示一直執(zhí)行到計時結束, 也可以用withRepeatCount(10), 表示到計時結束之前最多執(zhí)行10次
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever())
// 定義計時結束時間(年, 月, 日, 時, 分, 秒)
.endAt(new GregorianCalendar(2020, 11, 9, 22, 07, 30).getTime())
.build();

3.2 CronTrigger(重點)

適合于更復雜的任務,它支持類似于Linux Cron的語法(并且更強大)

  • 指定Cron表達式即可

示例:

// 不需要指定起始時間和結束時間
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
    // 表示定時在5月3日18時20分10秒時執(zhí)行任務
                    .withSchedule(CronScheduleBuilder.cronSchedule("10 20 18 3 5 ?")).build();

3.2.1 Cron表達式組成

表達式組成:"秒 分 時 日 月 星期幾 [年]",其中"年"是可選的,一般不指定

  • 如:"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(1代表周日,7代表周六) , - * ? / L #
7 年(可選) , - * /

3.2.2 Cron表達式的特殊值

  • ",":用來隔開幾個不連續(xù)的值。例如:"10,15,30 20 18 3 5 ?"表示 "5月3日18時20分的第10秒、15秒、30秒執(zhí)行一次任務,星期幾不確定"
  • "-":用來表示一段連續(xù)的值。例如:"10-30 20 18 3 5 ?"表示 "5月3日18時20分的第10秒第30秒執(zhí)行一次任務,星期幾不確定"
  • "" :表示任意值,即"每一個都"。例如:"10 * 18 3 5 ?"表示 "5月3日18時每一分鐘*的第10秒執(zhí)行一次任務,星期幾不確定"
  • "/" :表示步長。例如:"10/3 20 18 3 5 ?"表示 "5月3日18時20分的第10秒開始,每3秒執(zhí)行一次任務,星期幾不確定"
  • "?":表示不確定。因為日期和星期可能是會有沖突的,所以一般指定其中的一個另一個就用"?"可以避免發(fā)生沖突
  • "L":該字符只用在日期和星期中,表示"Last"。如果用在日期,則表示這個月份的最后一天;如果用在星期則表示星期六(等同于7);如果和數(shù)字一起用在星期,例如 6L,則表示該月的最后一個星期五
  • "W":該字符只用在日期中,表示"Work"工作日。例如 15W,表示距離該月(注意:不能跨月)15日最近的工作日;和L組合,LW表示該月的最后一個工作日

Cron表達式解析工具:http://bejson.com/othertools/cronvalidate/

四、Spring整合Quartz

4.1 Spring整合Quartz

Step1:導入依賴

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>

Step2:定義Job

/**
* 工作類的具體實現(xiàn), 即需要定時執(zhí)行的"某件事"
*/
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Job 定時執(zhí)行中 ..." + new Date());  // 打印時間, 方便觀察時間間隔
        // 可以從context中獲取JobDetail, 從而得到JobDetail的name和group
        JobDetail jobDetail = context.getJobDetail();
        JobKey key = jobDetail.getKey();
        System.out.println(key.getName());
        System.out.println(key.getGroup());
    }
}

Step3:編寫Spring的配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1. 定義JobDetail的bean, 作用是生產(chǎn)一個JobDetail, 這里使用JobDetailFactoryBean, 也可以使用MethodInvokingJobDetailFactoryBean, 配置類似 -->
    <bean id="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定JobDetail的name -->
        <property name="name" value="job1"/>
        <!-- 指定JobDetail的group -->
        <property name="group" value="job_group1"/>
        <!-- 指定具體的Job類(全類名) -->
        <property name="jobClass" value="com.lkf.quartz.MyJob"/>
    </bean>
    
    <!-- 2. 定義觸發(fā)器的bean, 作用是生產(chǎn)一個觸發(fā)器, 這里使用CronTrigger, 一個觸發(fā)器只能和一個任務進行綁定 -->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 指定觸發(fā)器的name -->
        <property name="name" value="trigger1"/>
        <!-- 指定觸發(fā)器的group -->
        <property name="group" value="trigger_group1"/>
        <!-- 指定觸發(fā)器綁定的JobDetail -->
        <property name="jobDetail" ref="myJobDetail"/>
        <!-- 指定Cron表達式-->
        <property name="cronExpression" value="* * * * * ?"/>
    </bean>
    
    <!-- 3. 定義調(diào)度器 -->
    <bean id="myScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 將觸發(fā)器注冊到調(diào)度器中 -->
        <property name="name" value="triggers">
            <list>
                <ref bean="myTrigger">
            </list>
        </property>
        <!-- 指定quartz配置文件 -->
        <property name="quartzProperties" value="classpath:quartz.properties"/>
    </bean>
</beans>

Step4:測試。啟動工廠即可

public class QuartzTest {
    @Test
    public void test() {
        // 工廠啟動, 任務啟動; 工廠關閉, 任務停止
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}

4.2 任務操作

4.2.1 刪除任務

public class QuartzTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 1. 獲取調(diào)度器
        StdScheduler scheduler = (StdScheduler)context.getBean("myScheduler");
        // 2. 過5秒鐘刪除任務
        Thread.sleep(5000);
        // 指定要刪除的JobDetail的name和group
        scheduler.deleteJob(JobKey.jobKey("job1", "job_group1"));  
    }
}

4.2.2 暫停、恢復任務

public class QuartzTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 1. 獲取調(diào)度器
        StdScheduler scheduler = (StdScheduler)context.getBean("myScheduler");
        // 2. 任務暫停過5秒鐘后恢復
        scheduler.pauseJob(JobKey.jobKey("job1", "job_group1"));
        Thread.sleep(5000);
        scheduler.resumeJob(JobKey.jobKey("job1", "job_group1"));  
    }
}

4.2.3 批量操作

只有暫停和恢復有批量操作

public class QuartzTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 1. 獲取調(diào)度器
        StdScheduler scheduler = (StdScheduler)context.getBean("myScheduler");
        // 2. 將一個group中的所有任務暫停過5秒鐘后恢復
        // 僅指定group的名稱即可
        scheduler.pauseJobs(GroupMacher.groupEquals("job_group1"));
        Thread.sleep(5000);
        scheduler.resumeJobs(GroupMacher.groupEquals("job_group1"));  
    }
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容