企業任務調度框架Quartz入門

定時任務,無論是互聯網行業還是傳統軟件行業都是不可少的。今天介紹的Quartz就是一款非常優秀的企業任務調度框架。

Quartz簡介

Quartz是OpenSymphony開源組織在Job scheduling領域的又一開源項目,它可以和J2EE或J2SE程序結合使用也可以單獨使用。小到獨立的應用,大到電子商業系統,Quartz都能夠創建執行成百上千甚至上萬的任務。簡而言之就是Quartz是基于Java實現的任務調度框架,可以執行你想執行的任何任務。

Quartz體系結構

Job
Job就是你想要實現的任務類,每一個Job必須實現org.quartz.job接口,且只需實現接口定義的execute方法。

JobDetail
JobDetail為Job實例提供了許多設置屬性以及JobDataMap成員變量屬性,它用來存儲特定Job實例的狀態信息。常見屬性name、group、jobClass、jobDataMap等

Trigger
觸發器,Trigger就是你執行任務的觸發器,定時去觸發你想要執行的任務。Trigger主要分為SimpleTrigger和CronTrigger兩種。

Scheduler
調度器,將任務Job和觸發器Trigger整合起來,負責根據Trigger設定的時間執行Job。


Quartz體系結構圖

入門例子

需求:每隔5秒鐘控制臺輸出一下當前時間,并傳遞數據給任務類。

/**
 * 定義要執行的任務類
 *  1.必須實現Job接口
 *  2.實現接口中的execute方法, 在該方法中編寫任務執行的業務邏輯
 *  3.每次執行Job時, 都會在調用execute方法前創建一個新的Job實例, 調用完成后, Job實例就會被釋放
 */
public class MyJob implements Job {

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //1.獲取當前時間
        LocalTime localTime = LocalTime.now();
        System.out.println("當前時間: "+localTime);
        //2.獲取trigger傳遞的數據
        String name = jobExecutionContext.getTrigger().getJobDataMap().getString("name");
        System.out.println("觸發器傳遞數據:"+name);
        //3.獲取jobDetail傳遞的數據
        int count = jobExecutionContext.getJobDetail().getJobDataMap().getInt("count");
        System.out.println("JobDetail傳遞數據:"+count);
    }

}
public static void main(String[] args) throws Exception{
    //1.定義任務調度器Scheduler并啟動
    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    scheduler.start();

    /**
     * 定義定時任務的實例JobDetail
     *    1.通過JobBuilder創建
     *    2.JobDetail為Job提供了很多設置屬性, 用來存儲Job實例的狀態信息
     */
    JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                                    //設置任務名稱和任務組名
                                    .withIdentity("myjob", "job-group")
                                    //設置JobDataMap, 可以在MyJob任務類中獲取到
                                    .usingJobData("count", 10)
                                    .build();

    //3.定義觸發器Trigger
    Trigger trigger = TriggerBuilder.newTrigger()
                                     //設置觸發器名稱和觸發器組名
                                    .withIdentity("trigger", "trigger-group")
                                    //設置JobDataMap, 可以在MyJob任務類中獲取到
                                    .usingJobData("name", "zhangsan")
                                     //每5秒觸發一次
                                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever())
                                    .build();

    //4.通過調度器關聯任務和觸發器
    scheduler.scheduleJob(jobDetail, trigger);
}

輸出:
當前時間: 16:56:27.579
觸發器傳遞數據:zhangsan
JobDetail傳遞數據:10
當前時間: 16:56:32.509
觸發器傳遞數據:zhangsan
JobDetail傳遞數據:10
....

Job

定時任務并發執行問題

在任務類上加@DisallowConcurrentExecution即可解決并發問題

@DisallowConcurrentExecution
public class MyJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    }
}

Job狀態

Job分為有狀態的Job和無狀態的Job
有狀態的Job:多次Job調用期間可以持有一些狀態信息,這些信息存儲在JobDataMap中
無狀態的Job:每次調用都會創建一個新的JobDataMap

# 沒有添加該注解,每次調用創建一個新的JobDataMap,不會累加
# 添加該注解,多次Job調用可以持有一些狀態信息
@PersistJobDataAfterExecution
public class HelloJob implements Job {
}

Trigger

Simple觸發器

簡單的觸發器,適合于按照時間間隔重復執行一項定時任務。

常用屬性:開始時間、結束時間、重復次數和重復間隔
重復次數:0、正整數、無限次執行
重復間隔:0(并發執行)、long類型(毫秒級)

Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger-name", "trigger-group")
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                                    .withIntervalInSeconds(5) //時間間隔:5秒
                                    .withRepeatCount(100)     //重復執行100次
                    )
                    .startAt(DateBuilder.futureDate(10, DateBuilder.IntervalUnit.SECOND)) //10秒后開始執行
                    .endAt(DateBuilder.futureDate(50, DateBuilder.IntervalUnit.SECOND))   //50秒后結束
                    .build();

Cron觸發器

按日歷方式觸發任務。

Cron表達式:由7個字表達式組成的字符串,每個表達式都描述了一個單獨的日程細節,表達式使用空格分割
1.秒
2.分
3.小時
4.天(月)
5.月
6.天(周)
7.年

字段 必須 特殊符號
0-59 , - * /
0-59 , - * /
0-23 , - * /
天(月) 1-31 , - * / ? L W C
1-12 或 JAN-DEC , - * /
1-7 或 SUN-SAT , - * / ? L C #
不填寫 或 1970-2099 , - * /
特殊符號 含義
* 用來表示域中每個可能的值
? 不指定值,忽略這個值
- 表示區間,比如3-5,就表示3,4,5
, 指定多個值, 比如3,4,5
/ 表示值的增量,例如分鐘域上0/2表示每個2分鐘從0開始
L last的簡寫,day of month中表示這個月的最后一天,day of week表示7(周六),在day of week域中6L表示最后一周的周5
W 用來指定距離給定日最近的周幾(在day of week域中指定),例如day of month域中指定12W表示距離12號最近的周幾
# 表示月中第幾個周幾,day of week中6#3表示月中第三個周五

示例
0 0 2,4,20 * * ? 每天上午2點4點, 下午20點執行
0 0/30 9-20 * * ? 每天早上9點到20點每隔半個小時執行一次
0 0 12 ? * WED 每個周三中午12點
0 0 12 * * ? 每天中午12點觸發
0 * 14 * * ? 每天下午14點到14點59每隔一分鐘執行一次

Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1") //觸發器名稱,觸發器組名稱
        //每5秒執行一次
        .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
        .build();

Trigger的優先級問題

Trigger默認優先級為5,只有在多個Trigger同時執行,并且線程數小于Trigger數量時才會有用。

    Trigger trigger = TriggerBuilder.newTrigger()
                                    .withIdentity("trigger", "trigger-group")
                                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever())
                                    .withPriority(6) //設置Trigger的優先級為6
                                    .build();

Scheduler調度器

StdSchedulerFactory

默認創建Scheduler的方式,使用一組參數(java.util.Properties)來創建和初始化Quartz調度器。
配置參數我們可以存儲在quartz.properties
調用getScheduler方法就能創建和初始化調度器對象

# 方式1
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

# 方式2
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

Scheduler

調度器,將任務Job和觸發器Trigger整合起來,負責根據Trigger設定的時間執行Job。

//將任務Job和觸發器Trigger整合起來, 并返回調度器開始時間
Date date = scheduler.scheduleJob(jobDetail, trigger);
//開啟任務調度
scheduler.start();
//掛起,即暫停操作
scheduler.standby();
//等所以正在執行的任務執行完畢,再關閉
scheduler.shutdown(true); 
//直接關閉
scheduler.shutdown(false);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容