springBoot整合 quartz動態定時任務
阿新 • • 發佈:2019-01-25
專案中需要用到定時任務,考慮了下java方面定時任務無非就三種:
- 用Java自帶的timer類。稍微看了一下,可以實現大部分的指定頻率的任務的排程(timer.schedule()),也可以實現關閉和開啟(timer.cancle)。但是用其來實現某天的某個時間或者某月的某一天排程任務有點不方便。
- 採用Quartz 排程器實現。這是一個功能很強大的開源的專門用於定時任務排程的框架,也很好的和springboot整合,缺點:配置複雜,需要花費一定的時間去了解和研究。
- spring3.0以後自帶的scheduletask任務排程,可以實現quartz的大部分功能,不需要額外引用jar,也不需要另外配置。而且支援註解和配置檔案兩種。
鑑於專案有些地方要考慮動態管理定時任務的,所以考慮吧quartz也整合進去,方便呼叫。
一、首先引入依賴(必需)
<!--任務排程相關依賴--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.3</version> </dependency>
二、建立job 例項工廠,解決spring注入問題,如果使用預設會導致spring的@Autowired 無法注入問題
1 package com.qunyi.jifenzhi_zx.core.quartz.taskjobfactory; 2 3TaskJobFactoryimport org.quartz.spi.TriggerFiredBundle; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 6 import org.springframework.scheduling.quartz.AdaptableJobFactory; 7 import org.springframework.stereotype.Component; 8 9 /** 10 * @author xujingyang 11 * @Description: 解決quartz無法注入spring bean問題 12 * @date 2018/5/30. 13 */ 14 @Component 15 public class TaskJobFactory extends AdaptableJobFactory { 16 @Autowired 17 private AutowireCapableBeanFactory capableBeanFactory; 18 19 @Override 20 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { 21 //呼叫父類的方法 22 Object jobInstance = super.createJobInstance(bundle); 23 //進行注入 24 capableBeanFactory.autowireBean(jobInstance); 25 return jobInstance; 26 } 27 }
三、建立job工具類,對job進行增加,暫停,恢復,更新,刪除等操作
1 package com.qunyi.jifenzhi_zx.core.quartz.taskjobfactory; 2 3 import com.qunyi.jifenzhi_zx.core.quartz.BaseTaskJob; 4 import org.quartz.*; 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.stereotype.Component; 9 10 /** 11 * @author xujingyang 12 * @Description: task任務建立工具 13 * @date 2018/5/30. 14 */ 15 @Component 16 public class TaskJobUtil { 17 private static final Logger logger = LoggerFactory.getLogger(TaskJobUtil.class); 18 19 private static TaskJobUtil jobUtil; 20 21 @Autowired 22 private Scheduler scheduler; 23 24 public TaskJobUtil() { 25 logger.info("init jobUtil"); 26 jobUtil = this; 27 } 28 29 public static TaskJobUtil getInstance() { 30 logger.info("retun JobCreateUtil"); 31 return TaskJobUtil.jobUtil; 32 } 33 34 /** 35 * 建立job 36 * 37 * @param clazz 任務類 38 * @param jobGroupName 任務所在組名稱 39 * @param cronExpression cron表示式 40 * @throws Exception 41 */ 42 public void addJob(Class clazz, String jobGroupName, String cronExpression) throws Exception { 43 44 // 啟動排程器 45 scheduler.start(); 46 47 //構建job資訊 48 JobDetail jobDetail = JobBuilder.newJob(((BaseTaskJob)clazz.newInstance()).getClass()).withIdentity(clazz.getSimpleName(), jobGroupName).build(); 49 50 //表示式排程構建器(即任務執行的時間) 51 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); 52 53 //按新的cronExpression表示式構建一個新的trigger 54 CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(clazz.getSimpleName(), jobGroupName) 55 .withSchedule(scheduleBuilder).build(); 56 scheduler.scheduleJob(jobDetail, trigger); 57 } 58 59 /** 60 * 暫停job 61 * 62 * @param jobClassName 任務類名稱 63 * @param jobGroupName 任務所在組名稱 64 * @throws SchedulerException 65 */ 66 public void pauseJob(String jobClassName, String jobGroupName) throws SchedulerException { 67 scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName)); 68 } 69 70 /** 71 * 恢復job 72 * 73 * @param jobClassName 任務類名稱 74 * @param jobGroupName 任務所在組名稱 75 * @throws SchedulerException 76 */ 77 public void resumeJob(String jobClassName, String jobGroupName) throws SchedulerException { 78 79 scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName)); 80 } 81 82 83 /** 84 * job 更新 85 * 86 * @param jobClassName 任務類名稱 87 * @param jobGroupName 任務所在組名稱 88 * @param cronExpression cron表示式 89 * @throws Exception 90 */ 91 public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception { 92 TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName); 93 // 表示式排程構建器 94 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); 95 96 CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); 97 98 // 按新的cronExpression表示式重新構建trigger 99 trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); 100 101 // 按新的trigger重新設定job執行 102 scheduler.rescheduleJob(triggerKey, trigger); 103 104 } 105 106 /** 107 * job 刪除 108 * 109 * @param jobClassName 任務類名稱 110 * @param jobGroupName 任務所在組名稱 111 * @throws Exception 112 */ 113 public void jobdelete(String jobClassName, String jobGroupName) throws Exception { 114 scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName)); 115 scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName)); 116 scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName)); 117 } 118 119 }TaskJobUtil
四、增加quartz 屬性配置檔案 quartz.properties,放置resource目錄下,此檔案主要提供schedule自動注入提供屬性
# 固定字首org.quartz org.quartz.scheduler.instanceName = DefaultQuartzScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.rmi.export = false org.quartz.scheduler.rmi.proxy = false org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
五、建立quartz的配置檔案QuartzrConfiguration,進行屬性配置
1 package com.qunyi.jifenzhi_zx.core.config; 2 3 import com.qunyi.jifenzhi_zx.core.quartz.taskjobfactory.TaskJobFactory; 4 import org.quartz.Scheduler; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.beans.factory.config.PropertiesFactoryBean; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Configuration; 9 import org.springframework.core.io.ClassPathResource; 10 import org.springframework.scheduling.quartz.SchedulerFactoryBean; 11 12 import javax.sql.DataSource; 13 import java.io.IOException; 14 15 /** 16 * @author xujingyang 17 * @Description: 任務排程配置 18 * @date 2018/5/30. 19 */ 20 @Configuration 21 public class QuartzConfiguration { 22 @Autowired 23 private DataSource dataSource; 24 @Autowired 25 private TaskJobFactory jobFactory; 26 27 @Bean(name = "SchedulerFactory") 28 public SchedulerFactoryBean schedulerFactoryBean() throws IOException { 29 //獲取配置屬性 30 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); 31 propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); 32 //在quartz.properties中的屬性被讀取並注入後再初始化物件 33 propertiesFactoryBean.afterPropertiesSet(); 34 //建立SchedulerFactoryBean 35 SchedulerFactoryBean factory = new SchedulerFactoryBean(); 36 factory.setQuartzProperties(propertiesFactoryBean.getObject()); 37 factory.setJobFactory(jobFactory); 38 return factory; 39 } 40 41 /* 42 * 通過SchedulerFactoryBean獲取Scheduler的例項 43 */ 44 @Bean(name = "scheduler") 45 public Scheduler scheduler() throws IOException { 46 return schedulerFactoryBean().getScheduler(); 47 } 48 }
六、建立基礎任務排程介面
1 package com.qunyi.jifenzhi_zx.core.quartz; 2 3 import org.quartz.Job; 4 import org.quartz.JobExecutionContext; 5 import org.quartz.JobExecutionException; 6 7 /** 8 * @author xujingyang 9 * @Description: 基礎任務排程taskJob介面 10 * @date 2018/5/30 11 * <p> 12 */ 13 public interface BaseTaskJob extends Job { 14 void execute(JobExecutionContext context) 15 throws JobExecutionException; 16 }
七、建立任務實現類
1 package com.qunyi.jifenzhi_zx.module.taskJob; 2 3 import com.qunyi.jifenzhi_zx.core.quartz.BaseTaskJob; 4 import org.quartz.JobExecutionContext; 5 import org.quartz.JobExecutionException; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.stereotype.Component; 9 10 @Component 11 public class TestQuartz implements BaseTaskJob { 12 13 Logger logger = LoggerFactory.getLogger(this.getClass()); 14 15 public int i = 0; 16 17 @Override 18 public void execute(JobExecutionContext context) throws JobExecutionException { 19 i++; 20 logger.error("task2>>>>>>> " + i); 21 22 try { 23 // TaskJobUtil.getInstance().jobdelete(this.getClass().getSimpleName(),"ah");//執行完此任務就刪除自己 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } 27 } 28 }
八、建立controller測試動態新增任務
1 @PostMapping("/task") 2 public void task(HttpServletRequest request) throws Exception { 3 String name = PrimaryKeyUtil.nextId(); 4 TaskJobUtil.getInstance().addJob(TestQuartz.class, name, "*/1 * * * * ?"); 5 }
九、訪問測試結果
總結及注意:
這種任務執行時是整個類都要初始化一遍的,不像spring的schedule只初始執行方法,這種每次執行類中的變數都會初始化。
新增新任務排程時,只需要新建類然後繼承任務介面實現方法即可,這樣在新增任務的時候只需要傳新建類的class就可以了。
傳同一個class的時候,是同一個任務方法,只不過新建了開了一個執行緒來執行而已。