SpringBoot中的定時任務與Quartz的整合


SpringBoot集成Quartz

定時任務Quartz : 就是在指定的時間執行一次或者循環執行,在項目的開發中有時候會需要的, 還是很有用的.

SpringBoot內置的定時

  1. 添加依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
  1. 啟動類上添加注解
@SpringBootApplication
@EnableScheduling
public class SpringbootQuartzApplication {
}
  1. 創建定時執行的任務類(兩種方式)

方式一:

@Component
public class SchedulerTask {
    
    private int count = 0;
    
    /**
     * @Author Smith
     * @Description 設置沒6秒執行一次
     * @Date 14:23 2019/1/24
     * @Param 
     * @return void
     **/
    @Scheduled(cron = "*/6 * * * * ?")
    private void process(){
        System.out.println("this is scheduler task running " + (count++));
    }
    
}

方式二:


@Component
public class SchedulerTask2 {
    
    private static final SimpleDateFormat dateFormat =
            new SimpleDateFormat("HH:mm:ss");
    
    /**
     * @Author Smith
     * @Description 設置沒6秒執行一次
     * @Date 14:22 2019/1/24
     * @Param 
     * @return void
     **/
    @Scheduled(fixedRate = 6000)
    private void process(){
        System.out.println("now time is " + dateFormat.format(new Date()));
    }
    
}

參數說明

@Scheduled 參數可以接受兩種定時的設置,一種是我們常用的 cron="*/6 * * * * ?",一種是 fixedRate = 6000,兩種都可表示固定周期執行定時任務。

fixedRate說明

  • @Scheduled(fixedRate = 6000):上一次開始執行時間點之后 6 秒再執行。
  • @Scheduled(fixedDelay = 6000):上一次執行完畢時間點之后 6 秒再執行。
  • @Scheduled(initialDelay=1000, fixedRate=6000):第一次延遲 1 秒后執行,之后按 fixedRate 的規則每 6 秒執行一次。

cron說明

cron一定有七位數,最后一位是年,SpringBoot定時方案只需要設置六位即可:

  • 第一位, 表示秒, 取值是0 ~ 59
  • 第二位, 表示分. 取值是0 ~ 59
  • 第三位, 表示小時, 取值是0 ~ 23
  • 第四位, 表示天/日, 取值是0 ~ 31
  • 第五位, 表示月份, 取值是1 ~ 12
  • 第六位, 表示星期, 取值是1 ~ 7, 星期一,星期二..., 還有 1 表示星期日
  • 第七位, 年份, 可以留空, 取值是1970 ~ 2099

cron中,還有一些特殊的符號,含義如下:

  • (*) 星號,可以理解為每的意思,每秒、每分、每天、每月、每年...。
  • (?)問號,問號只能出現在日期和星期這兩個位置,表示這個位置的值不確定,每天 3 點執行,因此第六位星期的位置,是不需要關注的,就是不確定的值;同時,日期和星期是兩個相互排斥的元素,通過問號來表明不指定值,比如 1 月 10 日是星期一,如果在星期的位置另指定星期二,就前后沖突矛盾了。
  • (-)減號,表達一個范圍,如在小時字段中使用“10 - 12”,則表示從 10 到 12 點,即 10、11、12。
  • (,)逗號,表達一個列表值,如在星期字段中使用“1,2,4”,則表示星期一、星期二、星期四。
  • (/)斜杠,如 x/y,x 是開始值,y 是步長,比如在第一位(秒),0/15 就是從 0 秒開始,每隔 15 秒執行一次,最后就是 0、15、30、45、60,另 */y,等同於 0/y。

舉幾個例子熟悉一下:

  • 0 0 3 * * ? :每天 3 點執行;
  • 0 5 3 * * ?:每天 3 點 5 分執行;
  • 0 5 3 ? * *:每天 3 點 5 分執行,與上面作用相同;
  • 0 5/10 3 * * ?:每天 3 點的 5 分、15 分、25 分、35 分、45 分、55分這幾個時間點執行;
  • 0 10 3 ? * 1:每周星期天,3 點 10 分執行,注,1 表示星期天;
  • 0 10 3 ? * 1#3:每個月的第三個星期,星期天執行,# 號只能出現在星期的位置。

基本上SpringBoot自帶的定時就是這么簡單了.

Quartz

建議寫代碼的時候下載下代碼來看看目錄結構
Quartz有四個核心概念:

  • Job:是一個接口,只定義一個方法 execute(JobExecutionContext context),在實現接口的 execute 方法中編寫所需要定時執行的 Job(任務),JobExecutionContext 類提供了調度應用的一些信息;Job 運行時的信息保存在 JobDataMap 實例中。
  • JobDetail:Quartz 每次調度 Job 時,都重新創建一個 Job 實例,因此它不接受一個 Job 的實例,相反它接收一個 Job 實現類(JobDetail,描述 Job 的實現類及其他相關的靜態信息,如 Job 名字、描述、關聯監聽器等信息),以便運行時通過 newInstance() 的反射機制實例化 Job。
  • rigger:是一個類,描述觸發 Job 執行的時間觸發規則,主要有 SimpleTrigger 和 CronTrigger 這兩個子類。當且僅當需調度一次或者以固定時間間隔周期執行調度,SimpleTrigger 是最適合的選擇;而 CronTrigger 則可以通過 Cron 表達式定義出各種復雜時間規則的調度方案:如工作日周一到周五的 15:00 ~ 16:00 執行調度等。
  • Scheduler:調度器就相當於一個容器,裝載着任務和觸發器,該類是一個接口,代表一個 Quartz 的獨立運行容器,Trigger 和 JobDetail 可以注冊到 Scheduler 中,兩者在 Scheduler 中擁有各自的組及名稱,組及名稱是 Scheduler 查找定位容器中某一對象的依據,Trigger 的組及名稱必須唯一,JobDetail 的組和名稱也必須唯一(但可以和 Trigger 的組和名稱相同,因為它們是不同類型的)。Scheduler 定義了多個接口方法,允許外部通過組及名稱訪問和控制容器中 Trigger 和 JobDetail。

quartz

Job 為作業的接口,為任務調度的對象;JobDetail 用來描述 Job 的實現類及其他相關的靜態信息;Trigger 做為作業的定時管理工具,一個 Trigger 只能對應一個作業實例,而一個作業實例可對應多個觸發器;Scheduler 做為定時任務容器,是 Quartz 最上層的東西,它提攜了所有觸發器和作業,使它們協調工作,每個 Scheduler 都存有 JobDetail 和 Trigger 的注冊,一個 Scheduler 中可以注冊多個 JobDetail 和多個 Trigger。

整合
  1. 引入依賴:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
  1. 定時輸出HelloWorld(使用Scheduler 啟動)

首先定義一個Job

public class SampleJob extends QuartzJobBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("Quartz ---->  Hello, " + this.name);
    }
}

構建JobDetail:

@Configuration
public class SampleScheduler {

    @Bean
    public JobDetail sampleJobDetail() {
        // 鏈式編程,可以攜帶多個參數,在Job類中聲明屬性 + setter方法
        return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob")
                .usingJobData("name","World").storeDurably().build();
    }

    @Bean
    public Trigger sampleJobTrigger(){
        // 每隔兩秒執行一次
        SimpleScheduleBuilder scheduleBuilder =
                SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever();
        return TriggerBuilder.newTrigger().forJob(sampleJobDetail()).withIdentity("sampleTrigger")
                .withSchedule(scheduleBuilder).build();
    }

}
  • JobBuilder 無構造函數,只能通過 JobBuilder 的靜態方法 newJob(Class jobClass)生成 JobBuilder 實例。
  • withIdentity 方法可以傳入兩個參數 withIdentity(String name,String group) 來定義 TriggerKey,也可以不設置,像上文示例中會自動生成一個獨一無二的 TriggerKey 用來區分不同的 Trigger。
  1. CronSchedule方式

CronSchedule可以設置更靈活的方式,定時設置與SpringBoot自帶的表達式相同.

同理,先定義兩個個Job,與ScheduledJob相同,不過實現Job接口,如下:

第一個job:

public class ScheduledJob implements Job {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

        System.out.println("CRON ----> schedule job1 is running ... + " + name + "  ---->  " + dateFormat.format(new Date()));
    }
}

第二個Job

public class ScheduledJob2 implements Job {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
        System.out.println("CRON ----> schedule job2 is running ... + " + name + "  ---->  " + dateFormat.format(new Date()));
    }
}

構建Schedule來執行任務:


@Component
public class CronSchedulerJob {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    private void scheduleJob1(Scheduler scheduler) throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class) .withIdentity("job1", "group1").build();
        // 6的倍數秒執行 也就是 6 12 18 24 30 36 42 ....
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/6 * * * * ?");
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                .usingJobData("name","王智1").withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail,cronTrigger);
    }

    private void scheduleJob2(Scheduler scheduler) throws SchedulerException{
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob2.class) .withIdentity("job2", "group2").build();
        // 12秒的倍數執行  12  24 36  48  60
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/12 * * * * ?");
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group2")
                .usingJobData("name","王智2").withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail,cronTrigger);
    }

    /**
     * @Author Smith
     * @Description 同時啟動兩個定時任務
     * @Date 16:31 2019/1/24
     * @Param
     * @return void
     **/
    public void scheduleJobs() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduleJob1(scheduler);
        scheduleJob2(scheduler);
    }
}

觸發定時任務有兩種方式:

第一種是項目啟動時執行:

@Component
public class MyStartupRunner implements CommandLineRunner {

    @Autowired
    public CronSchedulerJob scheduleJobs;

    @Override
    public void run(String... args) throws Exception {
        scheduleJobs.scheduleJobs();
        System.out.println(">>>>>>>>>>>>>>>定時任務開始執行<<<<<<<<<<<<<");
    }
}

第二種是定時執行:

@Configuration
@EnableScheduling
@Component
public class SchedulerListener {

    @Autowired
    public CronSchedulerJob scheduleJobs;

    @Scheduled(cron="0 47 16 24 1 ?")
    public void schedule() throws SchedulerException {
        scheduleJobs.scheduleJobs();
        System.out.println(">>>>>>>>>>>>>>>定時任務開始執行<<<<<<<<<<<<<");
    }

}

兩種啟動方案,在項目中選擇一種使用即可,否則會導致重復啟動定時任務而報錯。 所以在測試某一個啟動時,將另一個類上的注解注釋掉就可以了.

我剛開始工作,所以暫時還沒遇到定時任務方面需求,但是總感覺這個以后會用,提前學習一下,而且自我感覺這個定時任務也是挺有意思. 在SpringBoot自帶的定時器中我不知道能不能傳遞參數,但是quartz是可以,所以說如果需要傳遞參數的話就是用quartz絕對沒問題.

源碼: https://github.com/MissWangLove/SpringBoot


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM