SpringBoot下使用定時任務的方式全揭祕

假不理發表於2019-02-13

SpringBoot下使用定時任務的方式全揭祕

本文旨在用通俗的語言講述枯燥的知識

定時任務作為一種系統排程工具,在一些需要有定時作業的系統中應用廣泛,如每逢某個時間點統計資料、在將來某個時刻執行某些動作...定時任務在主流開發語言均提供相應的API供開發者呼叫,在Java中,實現定時任務有很多種方式,原生的方式實現一個完整定時任務需要由Timer、TimerTask兩個類,Timer是定時器類,用來按計劃開啟後臺執行緒執行指定任務,TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務。除此之外,還可以用ScheduledExecutorService類或者使用第三方jar庫Quartz,其中Quartz是一個優秀的定時任務框架,發展至今已經非常成熟,以致後來其他的定時任務框架的核心思想或底層大多源於Quartz。

springboot作為Java的一種開發框架,在springboot專案中實現定時任務不僅可以使用Java提供的原生方式,還可以使用springboot提供的定時任務API,下面,小編把Java原生和springboot所有的實現定時任務的方式做一個整合。

文章提綱: 1、使用執行緒 2、使用Timer類 3、使用ScheduledExecutorService類 4、使用Quartz 5、使用spring的@Scheduled註解 6、cron表示式

1. 執行緒實現

利用執行緒可以設定休眠時間的方式可以實現簡單的定時任務邏輯。

	public static void main(String[] args){
		//定時任務間隔時間
		int sleepTime=2*1000;
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true){
					try {
						System.out.println("Thread方式執行一次定時任務");
						//執行緒休眠規定時間
						Thread.sleep(sleepTime);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
複製程式碼

2. Timer類

Timer類允許排程一個TimerTask任務。使用這種方式可以讓你的程式按照某一個頻度執行。

	public static void main(String[] args){
		int sleepTime=2*1000;
		TimerTask timerTask = new TimerTask() {
			@Override
			public void run() {
				System.out.println("Timer方式執行一次定時任務");
			}
		};
		new Timer().schedule(timerTask,1,sleepTime);
	}
複製程式碼

3. ScheduledExecutorService類

ScheduledExecutorService,是基於執行緒池設計的定時任務類,每個排程任務都會分配到執行緒池中的一個執行緒去執行,也就是說,任務是併發執行,互不影響。 因此,基於ScheduledExecutorService類的定時任務類,歸根到底也是基於執行緒的排程實現的。

	public static void main(String[] args){
		int sleepTime=2*1000;
		ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
		scheduledExecutor.scheduleAtFixedRate(
				new Runnable() {
					@Override
					public void run() {
						System.out.println("ScheduledExecutorService方式執行一次定時任務");
					}
				}
		,1,sleepTime, TimeUnit.SECONDS);
	}
複製程式碼

4. 整合Quartz

Quartz是一個完全由Java編寫的開源作業排程框架,為在 Java 應用程式中進行作業排程提供了簡單卻強大的機制,要理解它的使用方式,需要先理解它的幾個核心概念:

  1. Job: 表示一個工作,要執行的具體內容。此介面中只有一個方法,如下: void execute(JobExecutionContext context)
  2. JobDetail: 表示一個具體的可執行的排程程式,Job 是這個可執行程排程程式所要執行的內容,另外 JobDetail 還包含了這個任務排程的方案和策略。
  3. Trigger: 代表一個排程引數的配置,什麼時候去調。
  4. Scheduler: 代表一個排程容器,一個排程容器中可以註冊多個 JobDetail 和Trigger。當 Trigger 與 JobDetail 組合,就可以被 Scheduler 容器排程了。

有了這些概念之後,我們就可以把Quartz整合到我們的springboot專案中了。

  1. 引入quartz依賴
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
複製程式碼
  1. 配置
@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail quartzDetail(){
        return JobBuilder.newJob(QuartzTest.class).withIdentity("QuartzTest").storeDurably().build();
    }
    @Bean
    public SimpleTrigger quartzTrigger(){
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(10)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(quartzDetail())
                .withIdentity("QuartzTest")
                .withSchedule(scheduleBuilder)
                .build();
    }
}
複製程式碼
  1. 測試
public class QuartzTest extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext){
        System.out.println("quartz執行一次定時任務 ");
    }
}
複製程式碼

5. 使用Scheduled註解

@Scheduled是spring為定時任務而生的一個註解,檢視註解的原始碼:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
//cron表示式
	String cron() default "";
//接收一個java.util.TimeZone#ID。
	String zone() default "";
//上一次執行完畢時間點之後多長時間再執行
	long fixedDelay() default -1;
//支援佔位符形式的字串型別的fixedDelay
	String fixedDelayString() default "";
//上一次開始執行時間點之後多長時間再執行
	long fixedRate() default -1;
//支援佔位符形式的字串型別的fixedRateString
	String fixedRateString() default "";
//第一次延遲多長時間後再執行	
	long initialDelay() default -1;
//支援佔位符形式的字串型別的initialDelay
	String initialDelayString() default "";
}
複製程式碼

可以看出:Scheduled註解中的引數用來設定“定時”動作,通常情況下,比較常用的引數是cron(),這意味著我們需要學會一些cron表示式相關的語法,但由於內容較多,篇幅較長,在這裡暫不鋪開講解,我們把cron語法相關放到文章最後,在此先講解如何用Scheduled註解來實現定時任務。

  1. 開啟定時任務支援
@SpringBootApplication
/**
 * 開啟定時任務支援
 */
@EnableScheduling
public class TestApplication  extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(this.getClass());
    }
}
複製程式碼
  1. 使用
@Component
public class ScheduledTest {
    private Logger logger = LoggerFactory.getLogger(ScheduledTest.class);
    /**
     * 每15秒執行一次定時任務
     */
    @Scheduled(cron = "0/15 * * * * ? ")
    public void testCron(){
        logger.info("Scheduled 執行一次定時任務");
    }
}
複製程式碼

6. cron表示式

cron表示式是一個字串其語法為:

[秒] [分] [小時] [日] [月] [周] [年]
複製程式碼

其中[年]為非必填項,因此通常cron表示式通常由6或7部分內容組成,內容的取值為數字或者一些cron表示式約定的特殊字元,這些特殊字元稱為“萬用字元”,每一個萬用字元分別代指一種值。cron表示式可以用這樣的表格來表示:

順序 取值範圍 特殊字串範圍
0~60 , - * /
0-60 , - * /
0-23 , - * /
1-31 , - * /
1-12 / JAN-DEC , - * ? / L W
1-7 / SUN-SAT , - * ? / L #
年(可省略) 1970-2099 , - * /

其中萬用字元的解釋以及作用如下:

萬用字元 代表的值 解釋
* 所有值 如:時欄位為*,代表每小時都觸發
? 不指定值 如:周欄位為?,代表表示式不關心是周幾
- 區間 如:時欄位設定2-5,代表2,3,4,5點鐘時都觸發
, 多個值 如:時欄位設定2,3,5,代表2,3,5點都會觸發
/ 遞增值 如:時欄位設定0/2,代表每兩個小時觸發,時欄位設定 2/5,代表從2時開始每隔5小時觸發一次
L 最後值 如:日欄位設定L,代表本月最後一天
W 最近工作日 如:在日欄位設定13W,代表沒約13日最近的那個工作日觸發一次
# 序號 如:在周欄位設定5#2,代表每月的第二個週五

示例: 每2秒執行一次:0/5 * * * * ? 每5分鐘執行一次:0 0/5 * * * ? 1分、12分、45分執行一次:0 1,12,45 * * * ? 每天23點59分59秒執行一次:59 59 23 * * ? 每月15號凌晨3點執行一次:0 0 3 15 * ? 每月最後一天12點執行一次:0 0 12 L * ?


覺得本文對你有幫助?請分享給更多人 關注「程式設計無界」,提升裝逼技能

SpringBoot下使用定時任務的方式全揭祕

相關文章