Quartz入門及觸發器與Trigger的介紹&&Spring task Vs Quartz的比較

不怕報錯 就怕不報錯的小猿猿發表於2020-12-03

轉載請標明出處:https://blog.csdn.net/men_ma/article/details/106847165.
本文出自 不怕報錯 就怕不報錯的小猿猿 的部落格

目標

1、Quartz簡介及應用場景
2、Quartz簡單觸發器 SimpleTrigger介紹
3、Quartz表示式觸發器CronTirgger介紹
4、Quartz中引數傳遞
5、Spring task Vs Quartz

1.Quartz簡介及應用場景

1. 1 Quartz介紹

任務排程框架“Quartz”是OpenSymphony開源組織在Job scheduling領域又一個開源專案,是完全由java開發的一個開源的任務日程管理系統,
“任務進度管理器”就是一個在預先確定(被納入日程)的時間到達時,負責執行(或者通知)其他軟體元件的系統。

簡單來說就是實現“計劃(或定時)任務”的系統,例如:訂單下單後未付款,15分鐘後自動撤消訂單,並自動解鎖鎖定的商品

1.2 Quartz的觸發器

觸發器用來告訴排程程式作業什麼時候觸發。框架提供了5種觸發器型別,但兩個最常用的SimpleTrigger和CronTrigger。

五種型別的Trigger(定時器)
SimpleTrigger,CronTirgger,DateIntervalTrigger,NthIncludedDayTrigger和Calendar類( org.quartz.Calendar)。

場景:
SimpleTrigger:執行N次,重複N次
CronTrigger:幾秒 幾分 幾時 哪日 哪月 哪周 哪年,執行

1.3. 儲存方式

RAMJobStore(記憶體作業儲存型別)和JDBCJobStore(資料庫作業儲存型別),兩種方式對比如下:

            優點                                    缺點

RAMJobStore 不要外部資料庫,配置容易,執行速度快 因為排程程式資訊是儲存在被分配給JVM的記憶體裡面,
所以,當應用程式停止執行時,所有排程資訊將被丟失。
另外因為儲存到JVM記憶體裡面,所以可以儲存多少個Job和Trigger將會受到限制

JDBCJobStor 支援叢集,因為所有的任務資訊都會儲存 執行速度的快慢取決與連線資料庫的快慢
到資料庫中,可以控制事物,還有就是如
果應用伺服器關閉或者重啟,任務資訊都
不會丟失,並且可以恢復因伺服器關閉或
者重啟而導致執行失敗的任務

圖解quartz工作流程
在這裡插入圖片描述
quartz相關表示式
線上生成表示式網址:http://cron.qqe2.com/

在這裡插入圖片描述
在這裡插入圖片描述
所需pom依賴

	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-aspects</artifactId>
	</dependency>
	<dependency>
           <groupId>org.quartz-scheduler</groupId>
           <artifactId>quartz</artifactId>
           <version>2.2.1</version>
      </dependency>
      <dependency>
           <groupId>org.quartz-scheduler</groupId>
           <artifactId>quartz-jobs</artifactId>
           <version>2.2.1</version>
      </dependency>

2.Quartz簡單觸發器 SimpleTrigger介紹

每次執行 * 長時間,每次間隔 * 長時間

package com.xiaoqing.quartz01.demo;

import com.xiaoqing.quartz01.job.RamJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.JobBuilder.newJob;

/**
 * @author晴sister
 * @site https://blog.csdn.net/men_ma
 * @company xxx公司
 * @create  2020-12-02 19:54
 *
 * quarts的入門級案例
 * 講解quartz定時任務呼叫過程
 */
public class Demo1 {
    public static void main(String[] args) throws Exception{
//        SchedulerFactory排程工廠
        SchedulerFactory schedulerFactory=new StdSchedulerFactory();
//      排程工廠生產排程器
        Scheduler scheduler=schedulerFactory.getScheduler();
//      獲取Job作業類
        JobDetail jobDetail=newJob(RamJob.class)
//               加上唯一標識, 就是用來標識作業類
                .withIdentity("job1","group1")
//                描述
                .withDescription("這是第一個定時任務案例....")
//                構建作業類
                .build();

//        構建觸發器(存放定時任務執行規則)
        Trigger trigger= (Trigger)TriggerBuilder.newTrigger()
//                定時任務每6s執行一次,一共會執行3次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(3,6))
                .withIdentity("trigger1","group1")
                .withDescription("這是第一個觸發器..")
                .build();

//        將作業類與觸發器組裝
        scheduler.scheduleJob(jobDetail,trigger);
//        啟動定時任務
        scheduler.start();
    }
}


作業類RamJob:

package com.xiaoqing.quartz01.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author晴sister
 * @site https://blog.csdn.net/men_ma
 * @company xxx公司
 * @create  2020-12-02 19:57
 */
public class RamJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.err.println("這裡就是定時任務啟動所會執行的程式碼庫");
        
}

在這裡插入程式碼片

執行結果
在這裡插入圖片描述

3.Quartz表示式觸發器CronTirgger介紹

一般我們都用表示式觸發器,因為它比較靈活

package com.xiaoqing.quartz01.demo;

import com.xiaoqing.quartz01.job.RamJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.JobBuilder.newJob;

/**
 * @author晴sister
 * @site https://blog.csdn.net/men_ma
 * @company xxx公司
 * @create  2020-12-02 19:54
 *
 * quarts的表示式觸發器
 *
 */
public class Demo2 {
    public static void main(String[] args) throws Exception{
        SchedulerFactory schedulerFactory=new StdSchedulerFactory();

        Scheduler scheduler=schedulerFactory.getScheduler();
        JobDetail jobDetail=newJob(RamJob.class)
                .withIdentity("job1","group1")
                .withDescription("這是第一個定時任務案例....")
                .build();

//        構建觸發器(存放定時任務執行規則)
        Trigger trigger= (Trigger)TriggerBuilder.newTrigger()
//                指定表達觸發器規則
//                表示式觸發器的第一個用途:從第5開始每3秒執行一次,無上限
//                .withSchedule(CronScheduleBuilder.cronSchedule("5/3 * * * * ?"))
//                表示式觸發器的第二個用途:在凌晨0.54的時候觸發定時任務
                .withSchedule(CronScheduleBuilder.cronSchedule("0 54 0 * * ?"))
//                    0/10 * * * * ?
//                .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
                .withIdentity("trigger1","group1")
                .withDescription("這是第一個觸發器..")
                .build();

//        將作業類與觸發器組裝
        scheduler.scheduleJob(jobDetail,trigger);
//        啟動定時任務
        scheduler.start();
    }
}

表示式觸發器的第一個用途:從第5開始每3秒執行一次,無上限
在這裡插入圖片描述

表示式觸發器的第二個用途:在凌晨0.54的時候觸發定時任務

在這裡插入圖片描述

4.Quartz中引數傳遞

package com.javaxl.quartz01.demo;

import com.javaxl.quartz01.job.RamJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.JobBuilder.newJob;

/**
 * @author 小李飛刀
 * @site www.javaxl.com
 * @company
 * @create  2019-11-14 9:33
 */
public class Demo3 {
    public static void main(String[] args) throws SchedulerException {
        SchedulerFactory factory = new StdSchedulerFactory();
//        排程器建立
        Scheduler scheduler = factory.getScheduler();

//        具體定時任務需要執行的程式碼
        JobDetail jobDetail = newJob(RamJob.class)
                .withIdentity("job2", "group1")
                .withIdentity("這是一個作業類案例")
                .build();

        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        jobDataMap.put("name","小李飛刀");
        jobDataMap.put("level","高階");
        jobDataMap.put("job","軟體開發");

        Trigger trigger = (Trigger) TriggerBuilder.newTrigger()
//                每6s執行一次
                .withSchedule(CronScheduleBuilder.cronSchedule("0/6 * * * * ?"))
//                定時定點執行
//                .withSchedule(CronScheduleBuilder.cronSchedule("0 52 09 * * ?"))
//                觸發器標識
                .withIdentity("trigger2", "group1")
                .withDescription("這是一個觸發器")
                .build();

//       排程工廠繫結作業類及觸發器
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
package com.javaxl.quartz01.job;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * @author 小李飛刀
 * @site www.javaxl.com
 * @company
 * @create  2019-11-14 9:32
 */
public class RamJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("基於RAM的quartz排程框架定時任務...");
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        System.out.println(jobDataMap.get("name").toString() + jobDataMap.get("level").toString() + jobDataMap.get("job"));
    }
}

5.Spring task Vs Quartz

  • Spring task

    優點:無需整合spring,作業類中就可以呼叫業務service
    缺點:單執行緒;不能做資料儲存型的定時任務

  • Quartz

    優點:多執行緒;可以做資料儲存型的定時任務,維護性高;
    缺點:需要整合spring,不能直接呼叫業務層service;

執行緒論證程式碼
Spring task程式碼

package com.xiaoqing.quartz01.tesk;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author晴sister
 * @site https://blog.csdn.net/men_ma
 * @company xxx公司
 * @create  2020-12-02 19:57
 */
@Service
public class SpringTask {
    @Scheduled(cron = "0/10 * * * * ?")
    public void xxx(){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.err.println(format.format(new Date())+" : 這是一個spring task...");

        try {
            Thread.sleep(20*1000);
            System.out.println("模擬正在處理大資料....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在啟動類加上註解@EnableScheduling:
在這裡插入圖片描述

結果是spring task中的定時任務變成了30s執行一次
在這裡插入圖片描述

Quartz程式碼

作業類RamJob:

package com.xiaoqing.quartz01.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

/**
 * @author晴sister
 * @site https://blog.csdn.net/men_ma
 * @company xxx公司
 * @create  2020-12-02 19:57
 */
public class RamJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//        System.err.println("這裡就是定時任務啟動所會執行的程式碼庫");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.err.println(format.format(new Date())+" : 這是一個quartz task...");

        try {
            Thread.sleep(20*1000);
            System.out.println("模擬正在處理大資料....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

修改觸發器的規則跟Spring task程式碼的規則一樣:

在這裡插入圖片描述
結果:不管前一個定時任務的執行緒是否結束,都會開啟下一個執行緒,依然每10s執行一次;

效果圖如下:
在這裡插入圖片描述

小結

quartz的核心類有以下三個需要牢記:
  • 排程器:Scheduler

  • 觸發器:Trigger

  • 作業類:JobDetail

相關文章