本片文章續《Spring Boot 入門(八):集成RabbitMQ消息隊列》,關於Quartz定時任務請參考《Quartz的基本使用之入門(2.3.0版本)》 spring boot實現定時任務,除了集成Quartz外,還可以直接使用scheduler註解。使用1個簡單的註解就可以完成,為什麼還要 ...
本片文章續《Spring Boot 入門(八):集成RabbitMQ消息隊列》,關於Quartz定時任務請參考《Quartz的基本使用之入門(2.3.0版本)》
spring boot實現定時任務,除了集成Quartz外,還可以直接使用scheduler註解。使用1個簡單的註解就可以完成,為什麼還要較為複雜的集成Quartz呢?這裡我簡單回答下這2中方式的區別,這也是我在項目中為什麼要選擇Quartz這種方式。
1.scheduler註解方式,一旦定時任務產生異常,那麼此定時任務就無法再次啟動,意味該定時任務就失效了,而Quartz不會。
2.scheduler註解方式,當前面的定時任務沒有完成的時候,無法再次開啟定時任務,這說明scheduler註解方式是單線程,而Quartz是多線程,同一定時任務可以併發處理。
3.scheduler註解方式,對於定時的格式很少,只能簡單的在註解中配置,很多複雜的定時任務沒法完成,而Quartz的格式很豐富,可以配置各種各樣的定時任務。
基於上述原因,定時任務應該選擇Quartz。
1.增加依賴
1 <!--quartz--> 2 <dependency> 3 <groupId>org.quartz-scheduler</groupId> 4 <artifactId>quartz</artifactId> 5 <version>2.2.1</version> 6 </dependency> 7 <!-- 該依賴必加,裡面有sping對schedule的支持 --> 8 <dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-context-support</artifactId> 11 </dependency>
2.增加conf
1 package 2 3 import org.quartz.*; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Service; 6 7 8 /** 9 * @program: 10 * @description: 定時任務創建job,通過註入Scheduler對任務進行操作 11 * @author: DZ 12 * @create: 2019-10-19 18:28 13 **/ 14 @Service 15 public class QuartzConf { 16 private static final String JOB_GROUP = "job_group"; 17 private static final String TRIGGER_GROUP = "trigger_group"; 18 @Autowired 19 private Scheduler scheduler; 20 21 /** 22 * 創建定時任務 23 *定義相應的任務(JobDetial)和觸發器(trigger),並將其加到一個執行日程(Scheduler)中,並通過監聽器啟動日程。 24 * @param jobDetailName 25 * @param cronExpression 26 * @param jobClass 27 * @throws SchedulerException 28 */ 29 public void createScheduleJob(String jobDetailName, String cronExpression, Class<? extends Job> jobClass) throws SchedulerException { 30 JobDetail jobDetail = JobBuilder.newJob(jobClass) 31 .withIdentity("task_" + jobDetailName, JOB_GROUP).storeDurably().requestRecovery().build(); 32 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); 33 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("task_" + jobDetailName, TRIGGER_GROUP).withSchedule(scheduleBuilder).build(); 34 scheduler.scheduleJob(jobDetail, trigger); 35 } 36 }
3.增加過濾器
6 import lombok.extern.slf4j.Slf4j; 7 import org.quartz.SchedulerException; 8 import org.slf4j.MDC; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.context.ApplicationListener; 11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.context.event.ContextRefreshedEvent; 13 14 import java.util.UUID; 15 16 /** 17 * @program: 18 * @description: 啟動監聽去初始化Quartz 19 * @author: DZ 20 * @create: 2019-10-19 18:32 21 **/ 22 @Slf4j 23 @Configuration 24 public class ApplicationStartQuartzJobListener implements ApplicationListener<ContextRefreshedEvent> { 25 @Autowired 26 private QuartzConf quartzConf; 27 28 /* 時間格式: 29 * * * * * * * 30 [秒] [分] [小時] [日] [月] [周] [年]*/ 31 32 /** 33 * 初始啟動quartz 34 */ 35 @Override 36 public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { 37 try { 38 log.info("任務開始啟動..."); 39 40 quartzConf.createScheduleJob("TestTask", "*/30 * * * * ?", TestTask.class); 41 log.info("任務已經啟動..."); 42 } catch (SchedulerException e) { 43 log.error("定時任務啟動失敗", e); 44 } 45 } 46 }
如果整個項目就一個定時任務,其實也不需要過濾器,直接將定時任務的類名寫在cong中即可。如果有多個定時任務,定義多個trigger和job也可以。這樣代碼的冗餘度比較高
此監聽器的作用在於:項目啟動的時候,監聽器將所有的定時任務註冊到日程中,相當於開啟定時任務。從而做到了只需要定義一套trigger和job就可以寫多個定時任務。
4.寫定時任務
1 2 3 4 import lombok.extern.slf4j.Slf4j; 5 import org.quartz.Job; 6 import org.quartz.JobExecutionContext; 7 import org.quartz.JobExecutionException; 8 import org.quartz.JobKey; 9 import org.slf4j.MDC; 10 11 import java.util.UUID; 12 13 /** 14 * @program: 15 * @description: 測試定時任務 16 * @author: DZ 17 * @create: 2019-10-19 18:49 18 **/ 19 @Slf4j 20 public class TestTask implements Job { 21 @Override 22 public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { 23 25 JobKey key = jobExecutionContext.getJobDetail().getKey(); 26 // todo 業務邏輯 27 log.info("----------" + key + "任務執行中,currentTime:" + DateUtil.getCurrentDate()); 28 } 29 }
這個位置除了實現Job介面外,還可以繼承QuartzJobBean類,其實QuartzJobBean也是Job的子類,只不過對部分參數進行了初始化
啟動服務,查看結果
此外,如果不對定時任務做線程池的配置,那麼預設是10個線程,這裡也可以增加對線程池的配置,在yml中增加屬性:
1 Spring: 2 # quartz定時器配置 3 quartz: 4 properties: 5 org: 6 quartz: 7 scheduler: 8 instanceName: quartzScheduler 9 instanceId: AUTO 10 threadPool: 11 class: org.quartz.simpl.SimpleThreadPool 12 threadCount: 20 13 threadPriority: 5 14 threadsInheritContextClassLoaderOfInitializingThread: true
此時就是定義了20個線程