在Spring Boot中實現定時任務功能,能夠經過Spring自帶的定時任務調度,也能夠經過集成經典開源組件Quartz實現任務調度。html
使用自帶的定時任務,很是簡單,只須要像下面這樣,加上註解就好,不須要像普通定時任務框架那樣繼承任何定時處理接口 ,簡單示例代碼以下:java
package com.power.demo.scheduledtask.simple; import com.power.demo.util.DateTimeUtil; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; @Component @EnableScheduling public class SpringTaskA { /** * CRON表達式參考:http://cron.qqe2.com/ **/ @Scheduled(cron = "*/5 * * * * ?", zone = "GMT+8:00") private void timerCron() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(timerCron)%s 每隔5秒執行一次,記錄日誌", DateTimeUtil.fmtDate(new Date()))); } }
上述代碼中,在一個類上添加@EnableScheduling註解,在方法上加上@Scheduled,配置下cron表達式,一個最最簡單的cron定時任務就完成了。cron表達式的各個組成部分,能夠參考下面:spring
@Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")
@Scheduled註解除了cron表達式,還有其餘配置方式,好比fixedRate和fixedDelay,下面這個示例經過配置方式的不一樣,實現不一樣形式的定時任務調度,示例代碼以下:服務器
package com.power.demo.scheduledtask.simple; import com.power.demo.util.DateTimeUtil; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; @Component @EnableScheduling public class SpringTaskB { /*fixedRate:上一次開始執行時間點以後5秒再執行*/ @Scheduled(fixedRate = 5000) public void timerFixedRate() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(fixedRate)如今時間:%s", DateTimeUtil.fmtDate(new Date()))); } /*fixedDelay:上一次執行完畢時間點以後5秒再執行*/ @Scheduled(fixedDelay = 5000) public void timerFixedDelay() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(fixedDelay)如今時間:%s", DateTimeUtil.fmtDate(new Date()))); } /*第一次延遲2秒後執行,以後按fixedDelay的規則每5秒執行一次*/ @Scheduled(initialDelay = 2000, fixedDelay = 5000) public void timerInitDelay() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(initDelay)如今時間:%s", DateTimeUtil.fmtDate(new Date()))); } }
注意一下主要區別:app
@Scheduled(fixedRate = 5000) :上一次開始執行時間點以後5秒再執行框架
@Scheduled(fixedDelay = 5000) :上一次執行完畢時間點以後5秒再執行ide
@Scheduled(initialDelay=2000, fixedDelay=5000) :第一次延遲2秒後執行,以後按fixedDelay的規則每5秒執行一次測試
有時候,不少項目咱們都須要配置好定時任務後當即執行一次,initialDelay就能夠不用配置了。spa
@Scheduled註解還有一個熟悉的屬性zone,表示時區,一般,若是不寫,定時任務將使用服務器的默認時區;若是你的任務想在特定時區特定時間點跑起來,好比常見的多語言系統可能會定時跑腳本更新數據,就能夠設置一個時區,如東八區,就能夠設置爲:3d
zone = "GMT+8:00"
Quartz是應用最爲普遍的開源任務調度框架之一,有不少公司都根據它實現本身的定時任務管理系統。Quartz提供了最經常使用的兩種定時任務觸發器,即SimpleTrigger和CronTrigger,本文以最普遍使用的CronTrigger爲例。
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency>
示例代碼須要,在application.properties文件中新增以下配置:
其實,咱們徹底能夠不用配置,直接在代碼裏面寫或者持久化在DB中而後讀取也能夠。
任務1:
package com.power.demo.scheduledtask.quartz; import com.power.demo.util.DateTimeUtil; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.util.Date; @DisallowConcurrentExecution public class QuartzTaskA implements Job { @Override public void execute(JobExecutionContext var1) throws JobExecutionException { try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(QuartzTaskA)%s 每隔3秒執行一次,記錄日誌", DateTimeUtil.fmtDate(new Date()))); } }
任務2:
定時發送郵件任務:
實現任務看上去很是簡單,繼承Quartz的Job接口,重寫execute方法便可。
怎麼讓Spring自動識別初始化Quartz定時任務實例呢?這就須要引用Spring管理的Bean,向Spring容器暴露所必須的bean,經過定義Job Factory實現自動注入。
首先,添加Spring注入的Job Factory類:
package com.power.demo.scheduledtask.quartz.config; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.quartz.SpringBeanJobFactory; public final class AutowireBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; /** * Spring提供了一種機制讓你能夠獲取ApplicationContext,即ApplicationContextAware接口 * 對於一個實現了ApplicationContextAware接口的類,Spring會實例化它的同時調用它的 * public voidsetApplicationContext(ApplicationContext applicationContext) throws BeansException;接口, * 將該bean所屬上下文傳遞給它。 **/ @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
定義QuartzConfig:
package com.power.demo.scheduledtask.quartz.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; @Configuration public class QuartzConfig { @Autowired @Qualifier("quartzTaskATrigger") private CronTriggerFactoryBean quartzTaskATrigger; @Autowired @Qualifier("quartzTaskBTrigger") private CronTriggerFactoryBean quartzTaskBTrigger; @Autowired @Qualifier("mailSendTrigger") private CronTriggerFactoryBean mailSendTrigger; //Quartz中的job自動注入spring容器託管的對象 @Bean public AutowireBeanJobFactory autoWiringSpringBeanJobFactory() { return new AutowireBeanJobFactory(); } @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean scheduler = new SchedulerFactoryBean(); scheduler.setJobFactory(autoWiringSpringBeanJobFactory()); //配置Spring注入的Job類 //設置CronTriggerFactoryBean,設定任務Trigger scheduler.setTriggers( quartzTaskATrigger.getObject(), quartzTaskBTrigger.getObject(), mailSendTrigger.getObject() ); return scheduler; } }
接着配置job明細:
package com.power.demo.scheduledtask.quartz.config; import com.power.demo.common.AppField; import com.power.demo.scheduledtask.quartz.MailSendTask; import com.power.demo.scheduledtask.quartz.QuartzTaskA; import com.power.demo.scheduledtask.quartz.QuartzTaskB; import com.power.demo.util.ConfigUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; @Configuration public class TaskSetting { @Bean(name = "quartzTaskA") public JobDetailFactoryBean jobDetailAFactoryBean() { //生成JobDetail JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(QuartzTaskA.class); //設置對應的Job factory.setGroup("quartzTaskGroup"); factory.setName("quartzTaskAJob"); factory.setDurability(false); factory.setDescription("測試任務A"); return factory; } @Bean(name = "quartzTaskATrigger") public CronTriggerFactoryBean cronTriggerAFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKA_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設置JobDetail stFactory.setJobDetail(jobDetailAFactoryBean().getObject()); stFactory.setStartDelay(1000); stFactory.setName("quartzTaskATrigger"); stFactory.setGroup("quartzTaskGroup"); stFactory.setCronExpression(cron); return stFactory; } @Bean(name = "quartzTaskB") public JobDetailFactoryBean jobDetailBFactoryBean() { //生成JobDetail JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(QuartzTaskB.class); //設置對應的Job factory.setGroup("quartzTaskGroup"); factory.setName("quartzTaskBJob"); factory.setDurability(false); factory.setDescription("測試任務B"); return factory; } @Bean(name = "quartzTaskBTrigger") public CronTriggerFactoryBean cronTriggerBFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKB_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設置JobDetail stFactory.setJobDetail(jobDetailBFactoryBean().getObject()); stFactory.setStartDelay(1000); stFactory.setName("quartzTaskBTrigger"); stFactory.setGroup("quartzTaskGroup"); stFactory.setCronExpression(cron); return stFactory; } @Bean(name = "mailSendTask") public JobDetailFactoryBean jobDetailMailFactoryBean() { //生成JobDetail JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(MailSendTask.class); //設置對應的Job factory.setGroup("quartzTaskGroup"); factory.setName("mailSendTaskJob"); factory.setDurability(false); factory.setDescription("郵件發送任務"); return factory; } @Bean(name = "mailSendTrigger") public CronTriggerFactoryBean cronTriggerMailFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKMAIL_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設置JobDetail stFactory.setJobDetail(jobDetailMailFactoryBean().getObject()); stFactory.setStartDelay(1000); stFactory.setName("mailSendTrigger"); stFactory.setGroup("quartzTaskGroup"); stFactory.setCronExpression(cron); return stFactory; } }
最後啓動你的Spring Boot定時任務應用,一個完整的基於Quartz調度的定時任務就實現好了。
本文定時任務示例中,有一個定時發送郵件任務MailSendTask,下一篇將分享Spring Boot應用中以MongoDB做爲存儲介質的簡易郵件系統。
擴展閱讀:
不少公司都會有本身的定時任務調度框架和系統,在Spring Boot中如何整合Quartz集羣,實現動態定時任務配置?
參考: