Spring Boot中实现定时任务应用实践

时间:2021-07-30 07:46:05

前言

在spring boot中实现定时任务功能,可以通过spring自带的定时任务调度,也可以通过集成经典开源组件quartz实现任务调度。

本文将详细介绍关于spring boot实现定时任务应用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

一、spring定时器

1、cron表达式方式

使用自带的定时任务,非常简单,只需要像下面这样,加上注解就好,不需要像普通定时任务框架那样继承任何定时处理接口 ,简单示例代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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表达式的各个组成部分,可以参考下面:

?
1
@scheduled(cron = "[seconds] [minutes] [hours] [day of month] [month] [day of week] [year]")

2、fixedrate和fixeddelay

@scheduled注解除了cron表达式,还有其他配置方式,比如fixedrate和fixeddelay,下面这个示例通过配置方式的不同,实现不同形式的定时任务调度,示例代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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、添加依赖

?
1
2
3
4
5
<dependency>
<groupid>org.quartz-scheduler</groupid>
<artifactid>quartz</artifactid>
<version>2.3.0</version>
</dependency>

2、配置cron表达式

示例代码需要,在application.properties文件中新增如下配置:

?
1
2
3
4
## quartz定时job配置
job.taska.cron=*/3 * * * * ?
job.taskb.cron=*/7 * * * * ?
job.taskmail.cron=*/5 * * * * ?

其实,我们完全可以不用配置,直接在代码里面写或者持久化在db中然后读取也可以。

3、添加定时任务实现

任务1:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

定时发送邮件任务:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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明细:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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集群,实现动态定时任务配置?

参考:

http://www.zzvips.com/article/159301.html

http://www.zzvips.com/article/159303.html

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/jeffwongishandsome/p/spring-boot-integrate-task-schedule-practise.html