如何在Spring Boot中實(shí)現(xiàn)定時(shí)任務(wù)?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
“只有客戶發(fā)展了,才有我們的生存與發(fā)展!”這是創(chuàng)新互聯(lián)的服務(wù)宗旨!把網(wǎng)站當(dāng)作互聯(lián)網(wǎng)產(chǎn)品,產(chǎn)品思維更注重全局思維、需求分析和迭代思維,在網(wǎng)站建設(shè)中就是為了建設(shè)一個(gè)不僅審美在線,而且實(shí)用性極高的網(wǎng)站。創(chuàng)新互聯(lián)對(duì)成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)站開(kāi)發(fā)、網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站優(yōu)化、網(wǎng)絡(luò)推廣、探索永無(wú)止境。
一、Spring定時(shí)器
1、cron表達(dá)式方式
使用自帶的定時(shí)任務(wù),非常簡(jiǎn)單,只需要像下面這樣,加上注解就好,不需要像普通定時(shí)任務(wù)框架那樣繼承任何定時(shí)處理接口 ,簡(jiǎn)單示例代碼如下:
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表達(dá)式參考: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秒執(zhí)行一次,記錄日志", DateTimeUtil.fmtDate(new Date()))); } } SpringTaskA
上述代碼中,在一個(gè)類上添加@EnableScheduling注解,在方法上加上@Scheduled,配置下 cron 表達(dá)式,一個(gè)最最簡(jiǎn)單的cron定時(shí)任務(wù)就完成了。cron表達(dá)式的各個(gè)組成部分,可以參考下面:
@Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")
2、fixedRate和fixedDelay
@Scheduled注解除了cron表達(dá)式,還有其他配置方式,比如fixedRate和fixedDelay,下面這個(gè)示例通過(guò)配置方式的不同,實(shí)現(xiàn)不同形式的定時(shí)任務(wù)調(diào)度,示例代碼如下:
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:上一次開(kāi)始執(zhí)行時(shí)間點(diǎn)之后5秒再執(zhí)行*/ @Scheduled(fixedRate = 5000) public void timerFixedRate() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(fixedRate)現(xiàn)在時(shí)間:%s", DateTimeUtil.fmtDate(new Date()))); } /*fixedDelay:上一次執(zhí)行完畢時(shí)間點(diǎn)之后5秒再執(zhí)行*/ @Scheduled(fixedDelay = 5000) public void timerFixedDelay() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(fixedDelay)現(xiàn)在時(shí)間:%s", DateTimeUtil.fmtDate(new Date()))); } /*第一次延遲2秒后執(zhí)行,之后按fixedDelay的規(guī)則每5秒執(zhí)行一次*/ @Scheduled(initialDelay = 2000, fixedDelay = 5000) public void timerInitDelay() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(initDelay)現(xiàn)在時(shí)間:%s", DateTimeUtil.fmtDate(new Date()))); } } SpringTaskB
注意一下主要區(qū)別:
@Scheduled(fixedRate = 5000)
:上一次開(kāi)始執(zhí)行時(shí)間點(diǎn)之后5秒再執(zhí)行
@Scheduled(fixedDelay = 5000)
:上一次執(zhí)行完畢時(shí)間點(diǎn)之后5秒再執(zhí)行
@Scheduled(initialDelay=2000, fixedDelay=5000)
:第一次延遲2秒后執(zhí)行,之后按fixedDelay的規(guī)則每5秒執(zhí)行一次
有時(shí)候,很多項(xiàng)目我們都需要配置好定時(shí)任務(wù)后立即執(zhí)行一次,initialDelay就可以不用配置了。
3、zone
@Scheduled注解還有一個(gè)熟悉的屬性zone,表示時(shí)區(qū),通常,如果不寫(xiě),定時(shí)任務(wù)將使用服務(wù)器的默認(rèn)時(shí)區(qū);如果你的任務(wù)想在特定時(shí)區(qū)特定時(shí)間點(diǎn)跑起來(lái),比如常見(jiàn)的多語(yǔ)言系統(tǒng)可能會(huì)定時(shí)跑腳本更新數(shù)據(jù),就可以設(shè)置一個(gè)時(shí)區(qū),如東八區(qū),就可以設(shè)置為:
zone = "GMT+8:00"
二、Quartz
Quartz是應(yīng)用最為廣泛的開(kāi)源任務(wù)調(diào)度框架之一,有很多公司都根據(jù)它實(shí)現(xiàn)自己的定時(shí)任務(wù)管理系統(tǒng)。Quartz提供了最常用的兩種定時(shí)任務(wù)觸發(fā)器,即SimpleTrigger和CronTrigger,本文以最廣泛使用的CronTrigger為例。
1、添加依賴
org.quartz-scheduler quartz 2.3.0
2、配置cron表達(dá)式
示例代碼需要,在application.properties文件中新增如下配置:
## Quartz定時(shí)job配置 job.taska.cron=*/3 * * * * ? job.taskb.cron=*/7 * * * * ? job.taskmail.cron=*/5 * * * * ?
其實(shí),我們完全可以不用配置,直接在代碼里面寫(xiě)或者持久化在DB中然后讀取也可以。
3、添加定時(shí)任務(wù)實(shí)現(xiàn)
任務(wù)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秒執(zhí)行一次,記錄日志", DateTimeUtil.fmtDate(new Date()))); } } QuartzTaskA
任務(wù)2:
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 QuartzTaskB implements Job { @Override public void execute(JobExecutionContext var1) throws JobExecutionException { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(String.format("(QuartzTaskB)%s 每隔7秒執(zhí)行一次,記錄日志", DateTimeUtil.fmtDate(new Date()))); } } QuartzTaskB
定時(shí)發(fā)送郵件任務(wù):
package com.power.demo.scheduledtask.quartz; import com.power.demo.service.contract.MailService; import com.power.demo.util.DateTimeUtil; import com.power.demo.util.PowerLogger; import org.joda.time.DateTime; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import java.util.Date; @DisallowConcurrentExecution public class MailSendTask implements Job { @Autowired private MailService mailService; @Override public void execute(JobExecutionContext var1) throws JobExecutionException { System.out.println(String.format("(MailSendTask)%s 每隔5秒發(fā)送郵件", DateTimeUtil.fmtDate(new Date()))); try { //Thread.sleep(1); DateTime dtNow = new DateTime(new Date()); Date startTime = dtNow.minusMonths(1).toDate();//一個(gè)月前 Date endTime = dtNow.plusDays(1).toDate(); mailService.autoSend(startTime, endTime); PowerLogger.info(String.format("發(fā)送郵件,開(kāi)始時(shí)間:%s,結(jié)束時(shí)間:%s" , DateTimeUtil.fmtDate(startTime), DateTimeUtil.fmtDate(endTime))); } catch (Exception e) { e.printStackTrace(); PowerLogger.info(String.format("發(fā)送郵件,出現(xiàn)異常:%s,結(jié)束時(shí)間:%s", e)); } } } MailSendTask
實(shí)現(xiàn)任務(wù)看上去非常簡(jiǎn)單,繼承Quartz的Job接口,重寫(xiě)execute方法即可。
4、集成Quartz定時(shí)任務(wù)
怎么讓Spring自動(dòng)識(shí)別初始化Quartz定時(shí)任務(wù)實(shí)例呢?這就需要引用Spring管理的Bean,向Spring容器暴露所必須的bean,通過(guò)定義Job Factory實(shí)現(xiàn)自動(dòng)注入。
首先,添加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提供了一種機(jī)制讓你可以獲取ApplicationContext,即ApplicationContextAware接口 * 對(duì)于一個(gè)實(shí)現(xiàn)了ApplicationContextAware接口的類,Spring會(huì)實(shí)例化它的同時(shí)調(diào)用它的 * 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; } } AutowireBeanJobFactory
定義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自動(dòng)注入spring容器托管的對(duì)象 @Bean public AutowireBeanJobFactory autoWiringSpringBeanJobFactory() { return new AutowireBeanJobFactory(); } @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean scheduler = new SchedulerFactoryBean(); scheduler.setJobFactory(autoWiringSpringBeanJobFactory()); //配置Spring注入的Job類 //設(shè)置CronTriggerFactoryBean,設(shè)定任務(wù)Trigger scheduler.setTriggers( quartzTaskATrigger.getObject(), quartzTaskBTrigger.getObject(), mailSendTrigger.getObject() ); return scheduler; } } QuartzConfig
接著配置job明細(xì):
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); //設(shè)置對(duì)應(yīng)的Job factory.setGroup("quartzTaskGroup"); factory.setName("quartzTaskAJob"); factory.setDurability(false); factory.setDescription("測(cè)試任務(wù)A"); return factory; } @Bean(name = "quartzTaskATrigger") public CronTriggerFactoryBean cronTriggerAFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKA_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設(shè)置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); //設(shè)置對(duì)應(yīng)的Job factory.setGroup("quartzTaskGroup"); factory.setName("quartzTaskBJob"); factory.setDurability(false); factory.setDescription("測(cè)試任務(wù)B"); return factory; } @Bean(name = "quartzTaskBTrigger") public CronTriggerFactoryBean cronTriggerBFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKB_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設(shè)置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); //設(shè)置對(duì)應(yīng)的Job factory.setGroup("quartzTaskGroup"); factory.setName("mailSendTaskJob"); factory.setDurability(false); factory.setDescription("郵件發(fā)送任務(wù)"); return factory; } @Bean(name = "mailSendTrigger") public CronTriggerFactoryBean cronTriggerMailFactoryBean() { String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKMAIL_CRON); CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); //設(shè)置JobDetail stFactory.setJobDetail(jobDetailMailFactoryBean().getObject()); stFactory.setStartDelay(1000); stFactory.setName("mailSendTrigger"); stFactory.setGroup("quartzTaskGroup"); stFactory.setCronExpression(cron); return stFactory; } } TaskSetting
springboot一種全新的編程規(guī)范,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程,SpringBoot也是一個(gè)服務(wù)于框架的框架,服務(wù)范圍是簡(jiǎn)化配置文件。
看完上述內(nèi)容,你們掌握如何在Spring Boot中實(shí)現(xiàn)定時(shí)任務(wù)的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!