项目开发中,经常需要定时任务来完成一些内容,如定时派息、跑批对账、业务监控等。Spring Boot体系中现在有两种方案可供选择,第一种是Spring Boot内置的注解方式,另一种是针对复杂的应用场景的Quartz。

一、Spring Boot内置定时

A、相关依赖

spring-boot-starter包中已经内置了定时的方法。



<dependency>



B、定时注解

在启动类添加上@EnableScheduling即可开启定时:



@SpringBootApplication



B、创建定时任务实现类

使用Spring Boot自带的定时非常的简单,只需要在方法上面添加@Scheduled注解即可。

1、使用cron表达式,定时执行。

cron一共有7位,最后一位是年,Spring Boot定时方案中只需要设置6位即可:



- 第一位,表示秒,取值 0-59;
- 第二位,表示分,取值 0-59;
- 第三位,表示小时,取值 0-23;
- 第四位,日期天/日,取值 1-31;
- 第五位,日期月份,取值 1-12;
- 第六位,星期,取值 1-7,星期一、星期二…;
注:不是第1周、第2周的意思,另外:1表示星期天,2表示星期一。
- 第七位,年份,可以留空,取值 1970-2099。



cron中,还有一些特殊的符号,含义如下:



(*)星号:可以理解为每的意思,每秒、每分、每天、每月、每年
(?)问号:问号只能出现在日期和星期这两个位置,表示这个位置的值不确定,每天 3 点执行,所以第六位星期的位置是不需要关注的,就是不确定的值。同时,日期和星期是两个相互排斥的元素,通过问号来表明不指定值。假如 1 月 10 日是星期一,如果在星期的位置是另指定星期二,就前后冲突矛盾了
(-)减号:表达一个范围,如在小时字段中使用“10-12”,则表示从 10~12 点,即 10、11、12
(,)逗号:表达一个列表值,如在星期字段中使用“1、2、4”,则表示星期一、星期二、星期四
(/)斜杠:如 x/y,x 是开始值,y 是步长,假设在第一位(秒) 0/15 就是,从 0 秒开始,每 15 秒,最后就是 0、15、30、45、60,另 */y,等同于 0/y



常用例子。



0 0 3 * * ?     每天 3 点执行
0 5 3 * * ?     每天 3 点 5 分执行
0 5 3 ? * *     每天 3 点 5 分执行
0 5/10 3 * * ?  每天 3 点的 5 分、15 分、25 分、35 分、45 分、55 分这几个时间点执行
0 10 3 ? * 1    每周日,3点10分 执行,注:1 表示周日
0 10 3 ? * 1#3  每个月的第 3 个星期,周日执行,# 号只能出现在星期的位置



了解了corn表达式之后,代码就很好控制了,具体可以通过http://cron.qqe2.com/,进行cron表达式测试。



@Slf4j



2、使用定时器进行规定周期调度。

  • @Scheduled(fixedRate = 6000) :上一次开始执行时间点之后6秒再执行
  • @Scheduled(fixedDelay = 6000) :上一次执行完毕时间点之后6秒再执行
  • @Scheduled(initialDelay=1000, fixedRate=6000) :第一次延迟1秒后执行,之后按fixedRate的规则每 6 秒执行一次。

以上注解也很好理解,就不多说明。



@Slf4j



启动项目之后,从日志中可以看到任务依次调度打印的结果。

cron方式,会根据cron表达式,于整点运行;但是fixedRate的方式则是从启动开始定时执行。



2019-05-20 08:20:44.395  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:20:44 - 0
2019-05-20 08:20:44.397  INFO 3208 --- [           main] t.c.j.JobSchedulerApplication            : Started JobSchedulerApplication in 0.649 seconds (JVM running for 1.829)
2019-05-20 08:20:45.001  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:20:45 - 0
2019-05-20 08:20:49.395  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:20:49 - 1
2019-05-20 08:20:50.001  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:20:50 - 1
2019-05-20 08:20:54.396  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:20:54 - 2
2019-05-20 08:20:55.001  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:20:55 - 2
2019-05-20 08:20:59.396  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:20:59 - 3
2019-05-20 08:21:00.001  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:21:00 - 3
2019-05-20 08:21:04.396  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:21:04 - 4
2019-05-20 08:21:05.001  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:21:05 - 4
2019-05-20 08:21:09.396  INFO 3208 --- [   scheduling-1] t.c.j.job.FixedRateSchedulerJob          : FixedRateSchedulerJob runing @08:21:09 - 5
2019-05-20 08:21:10.000  INFO 3208 --- [   scheduling-1] t.c.jobscheduler.job.CronSchedulerJob    : CronSchedulerJob runing @08:21:10 - 5



二、Quartz

A、Quartz介绍

当定时任务愈加复杂时,使用Spring注解@Schedule已经不能满足业务需要。Quartz是OpenSymphony开源组织在Job scheduling领域的一个开源项目,完全由Java开发的一个开源的任务日程管理系统,在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。

Quartz的优点

  • 丰富的Job操作API
  • 支持多种配置
  • Spring Boot无缝集成
  • 支持持久化
  • 支持集群
  • Quartz开源,是一个功能丰富的开源作业调度库,可以集成到几乎任何Java应用程序中

B、Quartz体系结构

Quartz核心概念:

  • Job(任务):为一个接口,只定义一个方法 execute(JobExecutionContext context),在实现接口的execute方法中编写所需要定时执行的 Job(任务),JobExecutionContext类提供了调度应用的一些信息。Job运行时的信息保存在JobDataMap实例中。
  • JobDetail(任务信息):Quartz每次调度Job时,都重新创建一个Job实例,它不直接接受一个Job的实例,相反它接收一个Job实现类(JobDetail,描述Job的实现类及其他相关的静态信息,如Job名字、描述、关联监听器等信息),以便运行时通过newInstance()的反射机制实例化Job。
  • Trigger(触发器):为一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案。
  • Scheduler(调度器):调度器就相当于一个容器,装载着任务和触发器。该类是一个接口,代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一, JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

四者其关系如下图所示:




android java 定时运行 java定时启动_定时执行


Job为作业的接口,为任务调度的对象;JobDetail用来描述Job的实现类及其他相关的静态信息;Trigger做为作业的定时管理工具,一个 Trigger只能对应一个作业实例,而一个作业实例可对应多个触发器;Scheduler做为定时任务容器,是quartz最上层的东西,它提携了所有触发器和作业,使它们协调工作,每个Scheduler都存有JobDetail和Trigger的注册,一个Scheduler中可以注册多个JobDetail和多个Trigger。

三、Spring Boot和Quartz

Spring Boot 1.x并没有提供Quartz的Starter支持包,因此网上的集成方案比较繁杂;Spring Boot 2.x提供了spring-boot-starter-quartz组件集成Quartz,使用Quartz变的非常简单。

A、相关依赖


<dependency>


B、SampleJob

配置完成之后使用SampleJob,通过Quartz定时输出 Hello World。

1、首先定义一个Job需要继承QuartzJobBean,示例中Job定义一个变量Name,用于在定时执行的时候传入。


@Slf4j


2、构建JobDetail,并且构建时传入name属性,构建JobTrigger和scheduleBuilder,最后使用Scheduler启动定时任务。


@Configuration


withIdentity方法可以传入两个参数withIdentity(String name,String group)来定义TriggerKey用来区分不同的trigger,也可以不设置。

C、CronSchedule

CronSchedule可以设置更灵活的使用方式,定时设置可以参考cron表达式。


@Slf4j


按照使用Quartz的逻辑,构建jobDetail、CronTrigger,最后使用scheduler关联jobDetail和CronTrigger。


@Component


使用scheduler启动两个定时任务。


public


D、触发定时任务

有两种方案来触发CronSchedule定时任务,一种是启动时调用scheduleJobs()启动定时任务,另外一种方案使用Spring Boot自带的Scheduled在特定时间触发启动。

1、启动时触发定时任务


@Slf4j


新建Runner,继承CommandLineRunner并重新run方法,在run方法中调用scheduleJobs()启动定时任务。

2、特定时间启动定时任务


@Component


一般情况下,使用第一种方案来启动定时任务;第二种方案设置固定日期时,需要考虑重复启动定时任务的情况,重复启动定时任务会报错。