天天看點

Quartz定時架構總結一、quartz介紹二、核心概念三、核心類和關系四、quartz使用

文章目錄

  • 一、quartz介紹
  • 二、核心概念
    • 1、trigger
    • 2、job
    • 3、scheduler
    • 4、作業管理和存儲
  • 三、核心類和關系
    • 1.核心類
    • 2.關系:
  • 四、quartz使用
    • 1.依賴
    • 2.原生應用
    • 3.Quartz+Spring內建使用

一、quartz介紹

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

Quartz用一個小Java庫釋出檔案(.jar檔案),這個庫檔案包含了所有Quartz核心功能。這些功能的主要接口(API)是Scheduler接口。它提供了簡單的操作,例如:将任務納入日程或者從日程中取消,開始/停止/暫停日程進度。

二、核心概念

Quartz定時架構總結一、quartz介紹二、核心概念三、核心類和關系四、quartz使用

Quartz 任務排程的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任務排程的中繼資料, scheduler 是實際執行排程的控制器。

1、trigger

觸發器,用于定于任務排程的時間規則,即按照什麼時間規則去執行任務。Quartz 中主要提供了四種類型的 trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger。Trigger也有一個相關聯的JobDataMap,用于給Job傳遞一些觸發相關的參數。

最常用的:

SimpleTrigger:用來觸發隻需執行一次或者在給定時間觸發并且重複N次且每次執行延遲一定時間的任務。

CronTrigger:按照月曆觸發,例如“每個周五”,每個月10日中午或者10:15分。

2、job

被排程的任務,主要有兩種類型的 job:無狀态的(stateless)和有狀态的(stateful)。

  1. Quartz無狀态Job實作了org.quartz.Job接口,有狀态Job實作了org.quartz.StatefulJob接口。
  2. 對于同一個 trigger 來說,有狀态的 job 不能被并行執行,隻有上一次觸發的任務被執行完之後,才能觸發下一次執行。
  3. 一個 job 可以被多個 trigger 關聯,但是一個 trigger 隻能關聯一個 job。

3、scheduler

任務排程器,由 scheduler 工廠建立:DirectSchedulerFactory 或者 StdSchedulerFactory。 第二種工廠 StdSchedulerFactory 使用較多,因為 DirectSchedulerFactory 使用起來不夠友善,需要作許多詳細的手工編碼設定。 Scheduler 主要有三種:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。

4、作業管理和存儲

作業一旦被排程,排程器需要記住并且跟蹤作業和它們的執行次數。Quartz通過一個稱之為作業存儲(JobStore)的概念來做作業存儲和管理。

Quartz提供兩種基本作業存儲類型。第一種類型叫做RAMJobStore,它利用記憶體來持久化排程程式資訊。

優點: 不要外部資料庫,配置容易,運作速度快

缺點: 因為排程程式資訊是存儲在被配置設定給JVM的記憶體裡面,是以,當應用程式停止運作時,所有排程資訊将被丢失。另外因為存儲到JVM記憶體裡面,是以可以存儲多少個Job和Trigger将會受到限制

第二種類型的作業存儲稱為JDBC作業存儲,提供兩種不同的實作。兩種JDBC作業存儲都需要JDBC驅動程式和背景資料庫來持久化排程程式資訊。這兩種類型的不同在于你是否想要控制資料庫事務或者釋放控制給應用伺服器(這類似于J2EE領域中,容器管理事務CMT和Bean管理事務BMT之間的差別),這兩種JDBC作業存儲是:

JobStoreTX:當你想要控制事務或工作在非應用伺服器環境中時使用;

JobStoreCMT:當你工作在應用伺服器環境中和想要容器控制事務時使用。

優點: 支援叢集,因為所有的任務資訊都會儲存到資料庫中,可以控制事物,還有就是如果應用伺服器關閉或者重新開機,任務資訊都不會丢失,并且可以恢複因伺服器關閉或者重新開機而導緻執行失敗的任務

缺點: 運作速度的快慢取決與連接配接資料庫的快慢

三、核心類和關系

1.核心類

  • QuartzSchedulerThread :負責執行向QuartzScheduler注冊的觸發Trigger的工作的線程。
  • ThreadPool:Scheduler使用一個線程池作為任務運作的基礎設施,任務通過共享線程池中的線程提供運作效率。
  • QuartzSchedulerResources:包含建立QuartzScheduler執行個體所需的所有資源(JobStore,ThreadPool等)。
  • SchedulerFactory :提供用于擷取排程程式執行個體的用戶端可用句柄的機制。
  • JobStore: 通過類實作的接口,這些類要為org.quartz.core.QuartzScheduler的使用提供一個org.quartz.Job和org.quartz.Trigger存儲機制。作業和觸發器的存儲應該以其名稱群組的組合為唯一性。
  • QuartzScheduler :這是Quartz的核心,它是org.quartz.Scheduler接口的間接實作,包含排程org.quartz.Jobs,注冊org.quartz.JobListener執行個體等的方法。
  • Scheduler :這是Quartz Scheduler的主要接口,代表一個獨立運作容器。排程程式維護JobDetails和觸發器的系統資料庫。 一旦注冊,排程程式負責執行作業,當他們的相關聯的觸發器觸發(當他們的預定時間到達時)。
  • Trigger :具有所有觸發器通用屬性的基本接口,描述了job執行的時間出發規則。 - 使用TriggerBuilder執行個體化實際觸發器。
  • JobDetail :傳遞給定作業執行個體的詳細資訊屬性。 JobDetails将使用JobBuilder建立/定義。
  • Job:要由表示要執行的“作業”的類實作的接口。隻有一個方法 void execute(jobExecutionContext context)

    (jobExecutionContext 提供排程上下文各種資訊,運作時資料儲存在jobDataMap中)

    Job有個子接口StatefulJob ,代表有狀态任務。

    有狀态任務不可并發,前次任務沒有執行完,後面任務處于阻塞等到。

2.關系:

Quartz定時架構總結一、quartz介紹二、核心概念三、核心類和關系四、quartz使用

四、quartz使用

1.依賴

<dependency>

    <groupId>org.quartz-scheduler</groupId>

    <artifactId>quartz</artifactId>
    
<version>2.2.3</version>
 
</dependency>
<dependency>

    <groupId>org.quartz-scheduler</groupId>

    <artifactId>quartz-jobs</artifactId>

    <version>2.2.3</version>
 
</dependency> 
           

2.原生應用

定義job

public class MyJob implements Job {
    private static Logger logger = LoggerFactory.getLogger(MyJob.class);
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //列印目前的執行時間 例如 2019-11-12 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("現在的時間是:"+ sf.format(date));
        //具體的業務邏輯
        System.out.println("開始生成任務報表 或 開始發送郵件");
        logger.info("開始執行定時任務");
    }
}
           

建立trigger,schedule,并啟動定時任務

//建立一個jobDetail的執行個體,将該執行個體與HelloJob Class綁定
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myJob").build();
//建立一個Trigger觸發器的執行個體,定義該job立即執行,并且每2秒執行一次,一直執行
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
//建立schedule執行個體
StdSchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail,trigger);
           

3.Quartz+Spring內建使用

先使用quartz自帶的建表語句建立表.

配置quartz.properties,如下:

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# 排程器執行個體的名字,使用預設的DefaultQuartzScheduler就好
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
# 排程器執行個體的ID, 選擇AUTO
org.quartz.scheduler.instanceId:AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
# 跳過更新檢查
org.quartz.scheduler.skipUpdateCheck:true
# 配置線程池
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#
# quartz預設的是将job資訊存儲在記憶體中,quartz叢集必須将job資訊持久化到資料庫中
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold:60000
############
org.quartz.jobStore.useProperties:true
#quartz資料表的字首,quartz的資料表在 quartz-2.2.3\docs\dbTables 檔案夾中,
#選擇對應的資料庫版本,将資料庫建立出來
org.quartz.jobStore.tablePrefix:QRTZ_
# 最關鍵的  是否支援叢集 選擇true
org.quartz.jobStore.isClustered:true
org.quartz.jobStore.clusterCheckinInterval:15000
# dataSource
#org.quartz.jobStore.dataSource:myDS
#org.quartz.dataSource.myDS.connectionProvider.class:com.abc.util.MyPoolingconnectionProvider
#org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver 
#org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8 
#org.quartz.dataSource.myDS.user: root 
#org.quartz.dataSource.myDS.password: root 
#org.quartz.dataSource.myDS.maxConnections: 10
           

db.properties:

#quartz配置對應資料庫
jdbc.quartz.driver=com.mysql.jdbc.Driver
jdbc.quartz.url=jdbc:mysql://127.0.0.1:26500/quartz?useUnicode=true&characterEncoding=utf-8
jdbc.quartz.username=root
jdbc.quartz.password=vislecaina
           

spring-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-4.0.xsd
                        ">

    <!-- 任務 -->
    <bean id="jobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.fiberhome.quartz.task.job.MyJob"/>
        <!-- 執行完成仍保留在資料庫中 -->
        <property name="durability" value="true"/>
        <!-- 這裡設定的jobDataAsMap可以傳遞一些參數給作業任務 -->
        <property name="jobDataAsMap">
            <map>
                <entry key="wish" value="hello"/>
            </map>
        </property>
    </bean>

    <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <!-- 這裡的JobDetail指的就是我們配置的作業任務的bean -->
        <property name="jobDetail" ref="jobDetailFactoryBeanExample" />
        <!-- 延遲5秒開始 -->
        <property name="startDelay" value="5000"></property>
        <!-- 每3秒重複一次 -->
        <property name="repeatInterval" value="60000"></property>
    </bean>

    <bean id="startQuartz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
        <property name="configLocation" value="classpath:quartz.properties" />
        <property name="dataSource" ref="quartzDataSource" />
        <!-- 如果這個覆寫配置為false,quratz啟動以後将以資料庫的資料為準,配置檔案的修改不起作用。-->
        <property name="overwriteExistingJobs" value="true" />
        <!--指定使用哪些觸發器,spring會去排程觸發相應的觸發器,進而對作業任務進行排程處理-->
        <property name="triggers">
            <list>
                <ref bean="simpleTrigger"/>
            </list>
        </property>
        <property name="jobFactory">
            <bean class="com.fiberhome.quartz.task.jobfactory.JobFactory"/>
        </property>
        <property name="startupDelay" value="1"/>
    </bean>

</beans>
           

Job類:

public class MyJob implements Job {

    @Autowired
    private UserService userService;
    /**
     * 要實作的任務
     *
     * @param context job上下文
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        User user = userService.getUser(1001);
        System.out.println("執行定時任務...");
        System.out.println(user);
    }
}
           

JobFactory類:

public class JobFactory extends SpringBeanJobFactory {

    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        autowireCapableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}