spring boot 系列之八:SpringBoot處理定時任務

JAVA開發老菜鳥發表於2021-09-07

專案經常會用到定時任務,springboot自然是可以通過整合相關元件來實現的。

目前常用的定時任務的實現有兩種:

  1. 通過spring 自帶的定時器任務@Schedule來實現
  2. 通過Quartz來實現

本次借用上一篇《spring boot 整合Mybatis》的既有專案結構進行案例除錯。

一、cron表示式

無論上面說的哪種實現方式,都需要用到cron表示式,因此不得不先介紹下它。

Cron表示式是一個字串,由6或7個域組成,每個域有不同的含義,每個域之間用空格隔開。有2中格式:

Seconds Minutes Hours DayofMonth Month DayofWeek Year (7個域)
Seconds Minutes Hours DayofMonth Month DayofWeek (6個域)

每個域可能出現的值:

Seconds:有效範圍為0-59的整數
Minutes:有效範圍為0-59的整數
Hours:有效範圍為0-23的整數
DayofMonth:有效範圍為0-31的整數
Month:有效範圍為1-12的整數或JAN-DEC
DayofWeek:有效範圍為1-7的整數或SUN-SAT兩個範圍。1表示星期天,2表示星期一, 依次類推
Year:有效範圍為1970-2099年

除了以上內容外,還可能出現一些特殊字元:

(1)*:表示匹配該域的任意值,假如在Minutes域使用*, 即表示每分鐘都會觸發事件。

(2)?:只能用在DayofMonth和DayofWeek兩個域。它也匹配域的任意值,但實際不會。因為DayofMonth和DayofWeek會相互影響。例如想在每月的10日觸發排程,不管10日到底是星期幾,則只能使用如下寫法: 13 13 15 10 * ?, 其中最後一位只能用?,而不能使用*,如果使用*表示不管星期幾都會觸發,實際上並不是這樣。 

(3)-:表示範圍,例如在Minutes域使用5-20,表示從5分到20分鐘每分鐘觸發一次 

(4)/:表示起始時間開始觸發,然後每隔固定時間觸發一次,例如在Minutes域使用5/20,則意味著5分鐘觸發一次,而25,45等分別觸發一次. 

(5),:表示列出列舉值值。例如:在Minutes域使用5,20,則意味著在5和20分每分鐘觸發一次。 

(6)L:表示最後,只能出現在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味著在最後的一個星期四觸發。 

(7)W:表示有效工作日(週一到週五),只能出現在DayofMonth域,系統將在離指定日期的最近的有效工作日觸發事件。例如:在 DayofMonth使用5W,如果5日是星期六,則將在最近的工作日:星期五,即4日觸發。如果5日是星期天,則在6日(週一)觸發;如果5日在星期一到星期五中的一天,則就在5日觸發。另外一點,W的最近尋找不會跨過月份 

(8)LW:這兩個字元可以連用,表示在某個月最後一個工作日,即最後一個星期五。 

(9)#:用於確定每個月第幾個星期幾,只能出現在DayofMonth域。例如在4#2,表示某月的第二個星期三。

舉例:

@Scheduled(cron = “0 0 1 1 1 ?”)//每年一月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 1,6 ?”) //一月和六月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 1,4,7,10 ?”) //每個季度的第一個月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 * ?”)//每月一號 1:00:00 執行一次

@Scheduled(cron=“0 0 1 * * *”) //每天凌晨 1 點執行一次

以上看上去有點複雜,不過不用擔心,記住常用的就行了。另外,現在網上還有 線上Cron表示式生成器可以幫助我們設定確定相關表示式內容。

二、@Schedule實現

1.引入依賴

<!--新增schedule依賴-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

2.程式碼實現

  1. 新建類JdkSchedule

    @Component
    public class JdkSchedule {
    
        @Autowired
        UserService userService;
    
        @Scheduled(cron = "0/2 * * * * ?") //每個兩秒觸發一次
        public void scheduleGetUserList() {
            System.out.println("**觸發JDK 定時器***");
            List<User> list = userService.getUserList(new User());
            for (User user :list ){
                System.out.println(user.toString());
            }
        }
    }
    

    裡面的userService為上一次新增的內容

  2. 啟動類新增註解,啟動定時任務

    @EnableScheduling
    

3.測試效果

每隔兩秒列印一次:

**觸發JDK 定時器***
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}

三、Quartz實現

1.Quartz介紹

Quartz是一個完全由Java編寫的開源任務排程的框架,通過觸發器設定作業定時執行規則,控制作業的執行時間。它包括排程器、觸發器、作業。

組成 描述
Job--任務 做什麼事?
Trigger--觸發器 什麼時候做?
Scheduler--排程器 什麼時候需要去做什麼事情?

2.基本使用

  • 引入依賴

    <!--引入quartz依賴-->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
    </dependency>
    
  • 建立job類

    public class MyJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("...quartz job 觸發執行...");
        }
    }
    

    需要實現Quartz的Job介面

  • 編寫測試類:

    /**
     * quartz原生態用法
     */
    public class JobTestMain {
        public static void main(String[] args) throws SchedulerException {
            //1.建立job
            JobDetail job = JobBuilder.newJob(MyJob.class).build();
    
            //2.建立trigger
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
                    .build();
    
            //3.建立schedule
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(job, trigger);
            scheduler.start();
        }
    }
    
  • 執行測試類JobTestMain:

    每三秒列印一次:

    ...quartz job 觸發執行...

3.springboot整合使用

  • 引入依賴

    <!--新增schedule依賴-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>
    
    <!--引入quartz依賴-->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
    </dependency>
    <!--引入spring tx依賴-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
    

    springboot整合的時候,需要新增這三個依賴。

  • 編寫配置類

    /**
     * springboot整合quartz使用方法
     */
    @Configuration
    public class QuartzConfig {
    
        /**
         * 建立job物件
         * @return
         */
        @Bean
        public JobDetailFactoryBean jobDetailFactoryBean() {
            JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
            jobDetailFactoryBean.setJobClass(MyJob.class);
            return jobDetailFactoryBean;
        }
    
        /**
         * 建立trigger物件 - cron表示式物件
         * @param jobDetailFactoryBean
         * @return
         */
        @Bean
        public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
            CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
            cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?");
            // 關聯JobDetail物件
            cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
            return cronTriggerFactoryBean;
        }
    
        /**
         * 建立trigger物件 - 一般物件
         * @param jobDetailFactoryBean
         * @return
         */
        @Bean
        public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
            SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
            // 關聯JobDetail物件
            simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
            // 設定重複次數,這裡配置的是重複次數,而不是總次數; 總次數=重複次數+1,也就是說這裡配置的次數是:執行完一次之後,再重複執行的次數
            simpleTriggerFactoryBean.setRepeatCount(1);
            // 設定間隔時間
            simpleTriggerFactoryBean.setRepeatInterval(2000);
            return simpleTriggerFactoryBean;
        }
    
        /**
         * 建立schedule物件
         * @param triggerFactoryBean
         * @return
         */
        @Bean
        public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean triggerFactoryBean){
            SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
            schedulerFactoryBean.setTriggers(triggerFactoryBean.getObject());
            return schedulerFactoryBean;
        }
    }
    

    這裡需要注意下,schedulerFactoryBean()方法中傳入的引數如果是CronTriggerFactoryBean,則執行的是cronTriggerFactoryBean()對應的設定;引數如果是SimpleTriggerFactoryBean,則執行的是simpleTriggerFactoryBean()對應的設定。

  • 啟動類新增註解

    @EnableScheduling

  • 測試效果

    每5秒鐘執行一次:

    ...quartz job 觸發執行...

    如果前面的@Schedule和這裡的Quartz的定時任務放在一起了,則執行效果為兩個Job一起執行:

    ...quartz job 觸發執行...
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    **觸發JDK 定時器***
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    **觸發JDK 定時器***
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    **觸發JDK 定時器***
    ...quartz job 觸發執行...
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    **觸發JDK 定時器***
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    **觸發JDK 定時器***
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    ...quartz job 觸發執行...
    

以上即為本文全部內容。

相關文章