1. 程式人生 > >Spring Boot2 系列教程(十六)定時任務的兩種實現方式

Spring Boot2 系列教程(十六)定時任務的兩種實現方式

在 Spring + SpringMVC 環境中,一般來說,要實現定時任務,我們有兩中方案,一種是使用 Spring 自帶的定時任務處理器 @Scheduled 註解,另一種就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具備這兩個 Spring 中的定時任務實現策略,當然也支援 Quartz,本文我們就來看下 Spring Boot 中兩種定時任務的實現方式。

@Scheduled

使用 @Scheduled 非常容易,直接建立一個 Spring Boot 專案,並且新增 web 依賴 spring-boot-starter-web

,專案建立成功後,新增 @EnableScheduling 註解,開啟定時任務:

@SpringBootApplication
@EnableScheduling
public class ScheduledApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScheduledApplication.class, args);
    }
}

接下來配置定時任務:

    @Scheduled(fixedRate = 2000)
    public void fixedRate() {
        System.out.println("fixedRate>>>"+new Date());    
    }
    @Scheduled(fixedDelay = 2000)
    public void fixedDelay() {
        System.out.println("fixedDelay>>>"+new Date());
    }
    @Scheduled(initialDelay = 2000,fixedDelay = 2000)
    public void initialDelay() {
        System.out.println("initialDelay>>>"+new Date());
    }
  1. 首先使用 @Scheduled 註解開啟一個定時任務。
  2. fixedRate 表示任務執行之間的時間間隔,具體是指兩次任務的開始時間間隔,即第二次任務開始時,第一次任務可能還沒結束。
  3. fixedDelay 表示任務執行之間的時間間隔,具體是指本次任務結束到下次任務開始之間的時間間隔。
  4. initialDelay 表示首次任務啟動的延遲時間。
  5. 所有時間的單位都是毫秒。

上面這是一個基本用法,除了這幾個基本屬性之外,@Scheduled 註解也支援 cron 表示式,使用 cron 表示式,可以非常豐富的描述定時任務的時間。cron 表示式格式如下:

[秒] [分] [小時] [日] [月] [周] [年]

具體取值如下:

序號 說明 是否必填 允許填寫的值 允許的萬用字元
1 0-59 - * /
2 0-59 - * /
3 0-23 - * /
4 1-31 - * ? / L W
5 1-12 or JAN-DEC - * /
6 1-7 or SUN-SAT - * ? / L ##
7 1970-2099 - * /

這一塊需要大家注意的是,月份中的日期和星期可能會起衝突,因此在配置時這兩個得有一個是 ?

萬用字元含義:

  • ? 表示不指定值,即不關心某個欄位的取值時使用。需要注意的是,月份中的日期和星期可能會起衝突,因此在配置時這兩個得有一個是 ?
  • * 表示所有值,例如:在秒的欄位上設定 *,表示每一秒都會觸發
  • , 用來分開多個值,例如在周欄位上設定 "MON,WED,FRI" 表示週一,週三和週五觸發
  • - 表示區間,例如在秒上設定 "10-12",表示 10,11,12秒都會觸發
  • / 用於遞增觸發,如在秒上面設定"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50)
  • ## 序號(表示每月的第幾個周幾),例如在周欄位上設定"6##3"表示在每月的第三個週六,(用 在母親節和父親節再合適不過了)
  • 周欄位的設定,若使用英文字母是不區分大小寫的 ,即 MON 與mon相同
  • L 表示最後的意思。在日欄位設定上,表示當月的最後一天(依據當前月份,如果是二月還會自動判斷是否是潤年), 在周欄位上表示星期六,相當於"7"或"SAT"(注意週日算是第一天)。如果在"L"前加上數字,則表示該資料的最後一個。例如在周欄位上設定"6L"這樣的格式,則表示"本月最後一個星期五"
  • W 表示離指定日期的最近工作日(週一至週五),例如在日欄位上設定"15W",表示離每月15號最近的那個工作日觸發。如果15號正好是週六,則找最近的週五(14號)觸發, 如果15號是周未,則找最近的下週一(16號)觸發,如果15號正好在工作日(週一至週五),則就在該天觸發。如果指定格式為 "1W",它則表示每月1號往後最近的工作日觸發。如果1號正是週六,則將在3號下週一觸發。(注,"W"前只能設定具體的數字,不允許區間"-")
  • LW 可以一組合使用。如果在日欄位上設定"LW",則表示在本月的最後一個工作日觸發(一般指發工資 )

例如,在 @Scheduled 註解中來一個簡單的 cron 表示式,每隔5秒觸發一次,如下:

@Scheduled(cron = "0/5 * * * * *")
public void cron() {
    System.out.println(new Date());
}

上面介紹的是使用 @Scheduled 註解的方式來實現定時任務,接下來我們再來看看如何使用 Quartz 實現定時任務。

Quartz

一般在專案中,除非定時任務涉及到的業務實在是太簡單,使用 @Scheduled 註解來解決定時任務,否則大部分情況可能都是使用 Quartz 來做定時任務。在 Spring Boot 中使用 Quartz ,只需要在建立專案時,新增 Quartz 依賴即可:

專案建立完成後,也需要新增開啟定時任務的註解:

@SpringBootApplication
@EnableScheduling
public class QuartzApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
    }
}

Quartz 在使用過程中,有兩個關鍵概念,一個是JobDetail(要做的事情),另一個是觸發器(什麼時候做),要定義 JobDetail,需要先定義 Job,Job 的定義有兩種方式:

第一種方式,直接定義一個Bean:

@Component
public class MyJob1 {
    public void sayHello() {
        System.out.println("MyJob1>>>"+new Date());
    }
}

關於這種定義方式說兩點:

  1. 首先將這個 Job 註冊到 Spring 容器中。
  2. 這種定義方式有一個缺陷,就是無法傳參。

第二種定義方式,則是繼承 QuartzJobBean 並實現預設的方法:

public class MyJob2 extends QuartzJobBean {
    HelloService helloService;
    public HelloService getHelloService() {
        return helloService;
    }
    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        helloService.sayHello();
    }
}
public class HelloService {
    public void sayHello() {
        System.out.println("hello service >>>"+new Date());
    }
}

和第1種方式相比,這種方式支援傳參,任務啟動時,executeInternal 方法將會被執行。

Job 有了之後,接下來建立類,配置 JobDetail 和 Trigger 觸發器,如下:

@Configuration
public class QuartzConfig {
    @Bean
    MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
        MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
        bean.setTargetBeanName("myJob1");
        bean.setTargetMethod("sayHello");
        return bean;
    }
    @Bean
    JobDetailFactoryBean jobDetailFactoryBean() {
        JobDetailFactoryBean bean = new JobDetailFactoryBean();
        bean.setJobClass(MyJob2.class);
        JobDataMap map = new JobDataMap();
        map.put("helloService", helloService());
        bean.setJobDataMap(map);
        return bean;
    }
    @Bean
    SimpleTriggerFactoryBean simpleTriggerFactoryBean() {
        SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
        bean.setStartTime(new Date());
        bean.setRepeatCount(5);
        bean.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
        bean.setRepeatInterval(3000);
        return bean;
    }
    @Bean
    CronTriggerFactoryBean cronTrigger() {
        CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
        bean.setCronExpression("0/10 * * * * ?");
        bean.setJobDetail(jobDetailFactoryBean().getObject());
        return bean;
    }
    @Bean
    SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean bean = new SchedulerFactoryBean();
        bean.setTriggers(cronTrigger().getObject(), simpleTriggerFactoryBean().getObject());
        return bean;
    }
    @Bean
    HelloService helloService() {
        return new HelloService();
    }
}

關於這個配置說如下幾點:

  1. JobDetail 的配置有兩種方式:MethodInvokingJobDetailFactoryBean 和 JobDetailFactoryBean 。
  2. 使用 MethodInvokingJobDetailFactoryBean 可以配置目標 Bean 的名字和目標方法的名字,這種方式不支援傳參。
  3. 使用 JobDetailFactoryBean 可以配置 JobDetail ,任務類繼承自 QuartzJobBean ,這種方式支援傳參,將引數封裝在 JobDataMap 中進行傳遞。
  4. Trigger 是指觸發器,Quartz 中定義了多個觸發器,這裡向大家展示其中兩種的用法,SimpleTrigger 和 CronTrigger 。
  5. SimpleTrigger 有點類似於前面說的 @Scheduled 的基本用法。
  6. CronTrigger 則有點類似於 @Scheduled 中 cron 表示式的用法。

全部定義完成後,啟動 Spring Boot 專案就可以看到定時任務的執行了。

總結

這裡主要向大家展示了 Spring Boot 中整合兩種定時任務的方法,整合成功之後,剩下的用法基本上就和在 SSM 中使用一致了,不再贅述。本文案例我已經上傳到 GitHub ,歡迎大家 star:https://github.com/lenve/javaboy-code-samples

關注公眾號【江南一點雨】,專注於 Spring Boot+微服務以及前後端分離等全棧技術,定期視訊教程分享,關注後回覆 Java ,領取鬆哥為你精心準備的 Java 乾貨!

相關推薦

Spring Boot2 系列教程()定時任務實現方式

在 Spring + SpringMVC 環境中,一般來說,要實現定時任務,我們有兩中方案,一種是使用 Spring 自帶的定時任務處理器 @Scheduled 註解,另一種就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具備這兩個 Spring

Spring Boot2 系列教程(二)@ControllerAdvice 的三使用場景

嚴格來說,本文並不算是 Spring Boot 中的知識點,但是很多學過 SpringMVC 的小夥伴,對於 @ControllerAdvice 卻並不熟悉,Spring Boot 和 SpringMVC 一脈相承,@ControllerAdvice 在 Spring Boot 中也有廣泛的使用場景,因此本文

Spring Boot2 系列教程(五)定義系統啟動任務方式

在 Servlet/Jsp 專案中,如果涉及到系統任務,例如在專案啟動階段要做一些資料初始化操作,這些操作有一個共同的特點,只在專案啟動時進行,以後都不再執行,這裡,容易想到web基礎中的三大元件( Servlet、Filter、Listener )之一 Listener ,這種情況下,一般定義一個 Serv

Spring Boot2 系列教程()Spring Boot 整合 Freemarker

今天來聊聊 Spring Boot 整合 Freemarker。 Freemarker 簡介 這是一個相當老牌的開源的免費的模版引擎。通過 Freemarker 模版,我們可以將資料渲染成 HTML 網頁、電子郵件、配置檔案以及原始碼等。Freemarker 不是面向終端使用者的,而是一個 Java 類庫,我

Spring Boot2 系列教程(一)Spring Boot 中的靜態資源配置

當我們使用 SpringMVC 框架時,靜態資源會被攔截,需要新增額外配置,之前老有小夥伴在微信上問鬆哥 Spring Boot 中的靜態資源載入問題:“鬆哥,我的 HTML 頁面好像沒有樣式?”,今天我就通過一篇文章,來和大夥仔細聊一聊這個問題。 1. SSM 中的配置 要講 Spring Boot 中的問

Spring Boot2 系列教程(四)CORS 解決跨域問題

今天和小夥伴們來聊一聊通過CORS解決跨域問題。 同源策略 很多人對跨域有一種誤解,以為這是前端的事,和後端沒關係,其實不是這樣的,說到跨域,就不得不說說瀏覽器的同源策略。 同源策略是由 Netscape 提出的一個著名的安全策略,它是瀏覽器最核心也最基本的安全功能,現在所有支援 JavaScript 的瀏覽

Spring Boot2 系列教程(七)SpringBoot 整合 Swagger2

前後端分離後,維護介面文件基本上是必不可少的工作。 一個理想的狀態是設計好後,介面文件發給前端和後端,大夥按照既定的規則各自開發,開發好了對接上了就可以上線了。當然這是一種非常理想的狀態,實際開發中卻很少遇到這樣的情況,介面總是在不斷的變化之中,有變化就要去維護,做過的小夥伴都知道這件事有多麼頭大!還好,有一

Spring Boot2 系列教程(八)Spring Boot 中自定義 SpringMVC 配置

用過 Spring Boot 的小夥伴都知道,我們只需要在專案中引入 spring-boot-starter-web 依賴,SpringMVC 的一整套東西就會自動給我們配置好,但是,真實的專案環境比較複雜,系統自帶的配置不一定滿足我們的需求,往往我們還需要結合實際情況自定義配置。 自定義配置就有講究了,由於

Spring Boot2 系列教程(九)Spring Boot 整合 JdbcTemplate

在 Java 領域,資料持久化有幾個常見的方案,有 Spring 自帶的 JdbcTemplate 、有 MyBatis,還有 JPA,在這些方案中,最簡單的就是 Spring 自帶的 JdbcTemplate 了,這個東西雖然沒有 MyBatis 那麼方便,但是比起最開始的 Jdbc 已經強了很多了,它沒有

Laravel框架定時任務2實現方式示例

本文例項講述了Laravel框架定時任務2種實現方式。分享給大家供大家參考,具體如下: 第一種 1、生成一個commands檔案 > php artisan make:command test 2、開啟檔案進行修改 laravel\App\Console\Commands\

Spring Boot2 系列教程(二)Spring Boot 整合 Redis

在 Redis 出現之前,我們的快取框架各種各樣,有了 Redis ,快取方案基本上都統一了,關於 Redis,鬆哥之前有一個系列教程,尚不瞭解 Redis 的小夥伴可以參考這個教程: Redis 教程合集 使用 Java 操作 Redis 的方案很多,Jedis 是目前較為流行的一種方案,除了 Jedi

Spring Boot2 系列教程()自定義 Spring Boot 中的 starter

我們使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 為我們帶來了眾多的自動化配置,有了這些自動化配置,我們可以不費吹灰之力就能搭建一個生產級開發環境,有的小夥伴會覺得這個 Starter 好神奇呀!其實 Starter 也都是 Spring + SpringMVC

Spring Boot2 系列教程(二一)整合 MyBatis

前面兩篇文章和讀者聊了 Spring Boot 中最簡單的資料持久化方案 JdbcTemplate,JdbcTemplate 雖然簡單,但是用的並不多,因為它沒有 MyBatis 方便,在 Spring+SpringMVC 中整合 MyBatis 步驟還是有點複雜的,要配置多個 Bean,Spring Boo

Spring Boot2 系列教程(二四)Spring Boot 整合 Jpa

Spring Boot 中的資料持久化方案前面給大夥介紹了兩種了,一個是 JdbcTemplate,還有一個 MyBatis,JdbcTemplate 配置簡單,使用也簡單,但是功能也非常有限,MyBatis 則比較靈活,功能也很強大,據我所知,公司採用 MyBatis 做資料持久化的相當多,但是 MyBat

Spring Boot2 系列教程(二五)Spring Boot 整合 Jpa 多資料來源

本文是 Spring Boot 整合資料持久化方案的最後一篇,主要和大夥來聊聊 Spring Boot 整合 Jpa 多資料來源問題。在 Spring Boot 整合JbdcTemplate 多資料來源、Spring Boot 整合 MyBatis 多資料來源以及 Spring Boot 整合 Jpa 多資料

Spring Boot2 系列教程(二八)Spring Boot 整合 Session 共享

這篇文章是鬆哥的原創,但是在第一次釋出的時候,忘了標記原創,結果被好多號轉發,導致我後來整理的時候自己沒法標記原創了。寫了幾百篇原創技術乾貨了,有一兩篇忘記標記原創進而造成的一點點小小損失也能接受,不過還是要和小夥伴們說明一下。 在傳統的單服務架構中,一般來說,只有一個伺服器,那麼不存在 Session

Spring Boot2 系列教程(二九)Spring Boot 整合 Redis

經過 Spring Boot 的整合封裝與自動化配置,在 Spring Boot 中整合Redis 已經變得非常容易了,開發者只需要引入 Spring Data Redis 依賴,然後簡單配下 redis 的基本資訊,系統就會提供一個 RedisTemplate 供開發者使用,但是今天鬆哥想和大夥聊的不是這種

Spring Boot2 系列教程(三)Spring Boot 整合 Ehcache

用慣了 Redis ,很多人已經忘記了還有另一個快取方案 Ehcache ,是的,在 Redis 一統江湖的時代,Ehcache 漸漸有點沒落了,不過,我們還是有必要了解下 Ehcache ,在有的場景下,我們還是會用到 Ehcache。 今天鬆哥就來和大家聊聊 Spring Boot 中使用 Ehcach

Spring Boot2 系列教程(三一)Spring Boot 構建 RESTful 風格應用

RESTful ,到現在相信已經沒人不知道這個東西了吧!關於 RESTful 的概念,我這裡就不做過多介紹了,傳統的 Struts 對 RESTful 支援不夠友好 ,但是 SpringMVC 對於 RESTful 提供了很好的支援,常見的相關注解有: @RestController @GetMapping

webpack4 系列教程():開發模式和生產模式·實戰

作者按:這是webpack4系列最後一篇教程了。這篇文章在之前所有教程的基礎上,做了一個真正意義上的 webpack 專案!我花費了三個月整理了這份教程,並且完善了相關示例程式碼,也更熟悉 webpack 的理論和應用,當然,也感謝大家的支援。好了,感慨完畢,