Spring Boot中实现定时任务应用实践
前言
在spring boot中实现定时任务功能,可以通过spring自带的定时任务调度,也可以通过集成经典开源组件quartz实现任务调度。
本文将详细介绍关于spring boot实现定时任务应用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
一、spring定时器
1、cron表达式方式
使用自带的定时任务,非常简单,只需要像下面这样,加上注解就好,不需要像普通定时任务框架那样继承任何定时处理接口 ,简单示例代码如下:
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()))); } } springtaska
上述代码中,在一个类上添加@enablescheduling注解,在方法上加上@scheduled,配置下 cron 表达式,一个最最简单的cron定时任务就完成了。cron表达式的各个组成部分,可以参考下面:
@scheduled(cron = "[seconds] [minutes] [hours] [day of month] [month] [day of week] [year]")
2、fixedrate和fixeddelay
@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()))); } } springtaskb
注意一下主要区别:
@scheduled(fixedrate = 5000)
:上一次开始执行时间点之后5秒再执行
@scheduled(fixeddelay = 5000)
:上一次执行完毕时间点之后5秒再执行
@scheduled(initialdelay=2000, fixeddelay=5000)
:第一次延迟2秒后执行,之后按fixeddelay的规则每5秒执行一次
有时候,很多项目我们都需要配置好定时任务后立即执行一次,initialdelay就可以不用配置了。
3、zone
@scheduled注解还有一个熟悉的属性zone,表示时区,通常,如果不写,定时任务将使用服务器的默认时区;如果你的任务想在特定时区特定时间点跑起来,比如常见的多语言系统可能会定时跑脚本更新数据,就可以设置一个时区,如东八区,就可以设置为:
zone = "gmt+8:00"
二、quartz
quartz是应用最为广泛的开源任务调度框架之一,有很多公司都根据它实现自己的定时任务管理系统。quartz提供了最常用的两种定时任务触发器,即simpletrigger和crontrigger,本文以最广泛使用的crontrigger为例。
1、添加依赖
<dependency> <groupid>org.quartz-scheduler</groupid> <artifactid>quartz</artifactid> <version>2.3.0</version> </dependency>
2、配置cron表达式
示例代码需要,在application.properties文件中新增如下配置:
## quartz定时job配置 job.taska.cron=*/3 * * * * ? job.taskb.cron=*/7 * * * * ? job.taskmail.cron=*/5 * * * * ?
其实,我们完全可以不用配置,直接在代码里面写或者持久化在db中然后读取也可以。
3、添加定时任务实现
任务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()))); } } quartztaska
任务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秒执行一次,记录日志", datetimeutil.fmtdate(new date()))); } } quartztaskb
定时发送邮件任务:
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秒发送邮件", datetimeutil.fmtdate(new date()))); try { //thread.sleep(1); datetime dtnow = new datetime(new date()); date starttime = dtnow.minusmonths(1).todate();//一个月前 date endtime = dtnow.plusdays(1).todate(); mailservice.autosend(starttime, endtime); powerlogger.info(string.format("发送邮件,开始时间:%s,结束时间:%s" , datetimeutil.fmtdate(starttime), datetimeutil.fmtdate(endtime))); } catch (exception e) { e.printstacktrace(); powerlogger.info(string.format("发送邮件,出现异常:%s,结束时间:%s", e)); } } } mailsendtask
实现任务看上去非常简单,继承quartz的job接口,重写execute方法即可。
4、集成quartz定时任务
怎么让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; } } 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自动注入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; } } quartzconfig
接着配置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; } } tasksetting
最后启动你的spring boot定时任务应用,一个完整的基于quartz调度的定时任务就实现好了。
本文定时任务示例中,有一个定时发送邮件任务mailsendtask,下一篇将分享spring boot应用中以mongodb作为存储介质的简易邮件系统。
扩展阅读:
很多公司都会有自己的定时任务调度框架和系统,在spring boot中如何整合quartz集群,实现动态定时任务配置?
参考:
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。