第 4-9 课:Spring Boot 集成 Quartz

在项⽬开发中,经常需要定时任务来帮助我们来做⼀些内容,⽐如定时派息、跑批对账、业务监控等。
Spring Boot 体系中现在有两种⽅案可以选择,第⼀种是 Spring Boot 内置的⽅式简单注解就可以使⽤,当然
如果需要更复杂的应⽤场景还是得 Quartz 上场, Quartz ⽬前是 Java 体系中最完善的定时⽅案。
⾸先来看看 Spring Boot ⾃带的定时⽅案。

Spring Boot 内置定时

pom 包配置

pom 包⾥⾯只需要引⼊ Spring Boot Starter 包即可,Spring Boot Starter 包中已经内置了定时的⽅法。

<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter</artifactId>
 </dependency>
</dependencies>

启动类开启定时

在启动类上⾯加上 @EnableScheduling 即可开启定时:
@Spring BootApplication
@EnableScheduling
public class Application {
 public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
 }
}

创建定时任务实现类

使⽤ Spring Boot ⾃带的定时⾮常的简单,只需要在⽅法上⾯添加 @Scheduled 注解即可。
定时任务 1
@Component
public class SchedulerTask {
 private int count=0;
 @Scheduled(cron="*/6 * * * * ?")
 private void process(){
 System.out.println("this is scheduler task runing "+(count++));
 }
}
设置 process() 每隔六秒执⾏⼀次,并统计执⾏的次数。
我们还有另外的⼀种⽅案来设置,固定时间周期执⾏⽅法,来看定时任务 2
@Component
public class Scheduler2Task {
 private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm
:ss");
 @Scheduled(fixedRate = 6000)
 public void reportCurrentTime() {
 System.out.println("现在时间:" + dateFormat.format(new Date()));
 }
}
启动项⽬之后,就会在控制台看到打印的结果。
结果如下:
this is scheduler task runing 0
现在时间:09:44:17
this is scheduler task runing 1
现在时间:09:44:23
this is scheduler task runing 2
现在时间:09:44:29
this is scheduler task runing 3
现在时间:09:44:35
说明两个⽅法都按照固定 6 秒的频率来执⾏。
参数说明
@Scheduled 参数可以接受两种定时的设置,⼀种是我们常⽤的 cron="*/6 * * * * ?" ,⼀种是 fifixedRate =
6000 ,两种都可表示固定周期执⾏定时任务。

fifixedRate 说明

  • @Scheduled(fifixedRate = 6000):上⼀次开始执⾏时间点之后 6 秒再执⾏。
  • @Scheduled(fifixedDelay = 6000):上⼀次执⾏完毕时间点之后 6 秒再执⾏。
  • @Scheduled(initialDelay=1000, fifixedRate=6000):第⼀次延迟 1 秒后执⾏,之后按 fifixedRate 的规则 6 秒执⾏⼀次。

cron 说明

 

cron ⼀共有七位,最后⼀位是年, Spring Boot 定时⽅案中只需要设置六位即可:
  • 第⼀位,表示秒,取值 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 点,即 101112
  • ,)逗号,表达⼀个列表值,如在星期字段中使⽤“124”,则表示星期⼀、星期⼆、星期四。
  • /)斜杠,如 x/yx 是开始值,y 是步⻓,⽐如在第⼀位(秒),0/15 就是从 0 秒开始,每隔 15 秒执 ⾏⼀次,最后就是 015304560,另 */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:每个⽉的第三个星期,星期天执⾏,# 号只能出现在星期的位置。
以上就是 Spring Boot ⾃定的定时⽅案,使⽤起来⾮常的简单⽅便。
 

Quartz

Quartz 介绍

Quartz OpenSymphony 开源组织在 Job Scheduling 领域⼜⼀个开源项⽬,是完全由 Java 开发的⼀个开
源任务⽇程管理系统, 任务进度管理器 就是⼀个在预先确定(被纳⼊⽇程)的时间到达时,负责执⾏(或
者通知)其他软件组件的系统。 Quartz 是⼀个开源的作业调度框架,它完全由 Java 写成,并设计⽤于
J2SE J2EE 应⽤中,它提供了巨⼤的灵活性⽽不牺牲简单性。
当定时任务愈加复杂时,使⽤ Spring 注解 @Schedule 已经不能满⾜业务需要。

Quartz 的优点

  • 丰富的 Job 操作 API
  • ⽀持多种配置;
  • Spring Boot ⽆缝集成;
  • ⽀持持久化;
  • ⽀持集群;
  • Quartz 还⽀持开源,是⼀个功能丰富的开源作业调度库,可以集成到⼏乎任何 Java 应⽤程序中。

Quartz 体系结构

 

明⽩ Quartz 怎么⽤,⾸先要了解 Job (任务)、 JobDetail (任务信息)、 Trigger (触发器)和
Scheduler (调度器)这 4 个核⼼的概念。
 
1 Job :是⼀个接⼝,只定义⼀个⽅法 execute JobExecutionContext context ),在实现接⼝的
execute ⽅法中编写所需要定时执⾏的 Job (任务), JobExecutionContext 类提供了调度应⽤的⼀些信息;
Job 运⾏时的信息保存在 JobDataMap 实例中。
 
2 JobDetail Quartz 每次调度 Job 时,都重新创建⼀个 Job 实例,因此它不接受⼀个 Job 的实例,相反
它接收⼀个 Job 实现类( JobDetail ,描述 Job 的实现类及其他相关的静态信息,如 Job 名字、描述、关联
监听器等信息),以便运⾏时通过 newInstance() 的反射机制实例化 Job
 
3 Trigger :是⼀个类,描述触发 Job 执⾏的时间触发规则,主要有 SimpleTrigger CronTrigger 这两个
⼦类。当且仅当需调度⼀次或者以固定时间间隔周期执⾏调度, SimpleTrigger 是最适合的选择;⽽
CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度⽅案:如⼯作⽇周⼀到周五的 15 00
~ 16 00 执⾏调度等。
 
4 Scheduler :调度器就相当于⼀个容器,装载着任务和触发器,该类是⼀个接⼝,代表⼀个 Quartz 的独
⽴运⾏容器, Trigger JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各⾃的组及名称,组
及名称是 Scheduler 查找定位容器中某⼀对象的依据, Trigger 的组及名称必须唯⼀, JobDetail 的组和名称
也必须唯⼀(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。 Scheduler 定义了多个接⼝⽅
法,允许外部通过组及名称访问和控制容器中 Trigger JobDetail
 
四者其关系如下图所示:
Job 为作业的接⼝,为任务调度的对象; JobDetail ⽤来描述 Job 的实现类及其他相关的静态信息; Trigger
做为作业的定时管理⼯具,⼀个 Trigger 只能对应⼀个作业实例,⽽⼀个作业实例可对应多个触发器;
Scheduler 做为定时任务容器,是 Quartz 最上层的东⻄,它提携了所有触发器和作业,使它们协调⼯作,每
Scheduler 都存有 JobDetail Trigger 的注册,⼀个 Scheduler 中可以注册多个 JobDetail 和多个
Trigger

Spring Boot Quartz

Spring Boot 2.0 提供了 spring-boot-starter-quartz 组件集成 Quartz ,让我们在项⽬中使⽤ Quartz 变得简 单。

配置内容

配置 pom.xml

添加 spring-boot-starter-quartz 组件:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

简单示例

配置完成之后先来做⼀个最简单的示例,使⽤ Quartz 定时输出 Hello World
⾸先定义⼀个 Job 需要继承 QuartzJobBean ,示例中 Job 定义⼀个变量 Name ,⽤于在定时执⾏的时候传
⼊。
public class SampleJob extends QuartzJobBean {
 private String name;
 public void setName(String name) {
 this.name = name;
 }
 @Override
 protected void executeInternal(JobExecutionContext context)
 throws JobExecutionException {
 System.out.println(String.format("Hello %s!", this.name));
 }
}
接下来构建 JobDetail ,并且构建时传⼊ name 属性的值,构建 JobTrigger scheduleBuilder ,最后使⽤
Scheduler 启动定时任务。
@Configuration
public class SampleScheduler {
 @Bean
 public JobDetail sampleJobDetail() {
 return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob")
 .usingJobData("name", "World").storeDurably().build();
 }
 @Bean
 public Trigger sampleJobTrigger() {
 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedu
le()
 .withIntervalInSeconds(2).repeatForever();
 return TriggerBuilder.newTrigger().forJob(sampleJobDetail())
 .withIdentity("sampleTrigger").withSchedule(scheduleBuilder).build
();
 }
}
  • JobBuilder ⽆构造函数,只能通过 JobBuilder 的静态⽅法 newJob(Class<? extends Job> jobClass) JobBuilder 实例。
  • withIdentity ⽅法可以传⼊两个参数 withIdentity(String name,String group) 来定义 TriggerKey,也可以 不设置,像上⽂示例中会⾃动⽣成⼀个独⼀⽆⼆的 TriggerKey ⽤来区分不同的 Trigger
启动项⽬后每隔两秒输出: Hello World!
Hello World!
Hello World!
Hello World!
...

CronSchedule 示例

CronSchedule 可以设置更灵活的使⽤⽅式,定时设置可以参考上⾯的 cron 表达式。
 
⾸先定义两个 Job
public class ScheduledJob implements Job {
 @Override 
 public void execute(JobExecutionContext context) throws JobExecutionException 
{
 System.out.println("schedule job1 is running ...");
 } 
}
ScheduledJob2 ScheduledJob 代码基本⼀致。
按照使⽤ Quartz 的逻辑,构建 jobDetail CronTrigger ,最后使⽤ scheduler 关联 jobDetail
CronTrigger scheduleJob1 设置每间隔 6 秒执⾏⼀次。
private void scheduleJob1(Scheduler scheduler) throws SchedulerException{
 JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class) .withIdentity("job
1", "group1").build();
 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/6 * 
* * * ?");
 CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1",
 "group1") .withSchedule(scheduleBuilder).build();
 scheduler.scheduleJob(jobDetail,cronTrigger); 
}
  • CronScheduleBuilder.cronSchedule("0/6 * * * * ?"),按照 cron 表达式设置定时任务的执⾏周期。
ScheduleJob2 的内容和 ScheduleJob1 基本⼀致,时间设置为间隔 12 秒执⾏⼀次。
使⽤ Scheduler 启动两个定时任务。
public void scheduleJobs() throws SchedulerException {
 Scheduler scheduler = schedulerFactoryBean.getScheduler();
 scheduleJob1(scheduler);
 scheduleJob2(scheduler); 
}

何时触发定时任务

我们有两种⽅案来触发 CronSchedule 定时任务,⼀种是启动时调⽤ scheduleJobs() 来启动定时任务,另外
⼀种⽅案使⽤ Spring Boot ⾃带的 Scheduled 在特定时间触发启动。
 
第⼀种⽅案,启动时触发定时任务:
@Component
public class MyStartupRunner implements CommandLineRunner {
 @Autowired
 public CronSchedulerJob scheduleJobs;
 @Override
 public void run(String... args) throws Exception {
 scheduleJobs.scheduleJobs();
 System.out.println(">>>>>>>>>>>>>>>定时任务开始执⾏<<<<<<<<<<<<<");
 }
}
定时⼀个 Runner ,继承 CommandLineRunner 并重新 run ⽅法,在 run ⽅法中调⽤ scheduleJobs() 来启动
定时任务。
 
第⼆种⽅案,特定时间启动定时任务:
@Configuration
@EnableScheduling
@Component
public class SchedulerListener { 
 @Autowired
 public CronSchedulerJob scheduleJobs;
 @Scheduled(cron="0 30 11 25 11 ?")
 public void schedule() throws SchedulerException {
 scheduleJobs.scheduleJobs();
 } 
}
启动项⽬后每隔 6 秒输出 job1 内容,每隔 12 秒输出 job2 内容,再加上上⾯示例每两秒输出的 Hello
World ,输出内容如下: GitChat
Hello World!
Hello World!
Hello World!
schedule job1 is running ...
Hello World!
Hello World!
Hello World!
schedule job1 is running ...
schedule job2 is running ...
...
⼀般情况下,建议使⽤第⼀种⽅案来启动定时任务;第⼆种⽅案设置固定⽇期时,需要考虑重复启动定时任
务的情况,重复启动定时任务会报错。
注意,两种启动⽅案,在项⽬中选择⼀种使⽤即可,否则会导致重复启动定时任务⽽报错。

总结

通过上⾯的示例可以看出,如果仅需要执⾏简单定时任务,就可以使⽤ Spring Boot ⾃带 Scheduled ,⾮常
简单、⽅便;但如果需要在项⽬中执⾏⼤量的批任务处理时,可以采⽤ Quartz 来解决, Spring Boot 2.0
提供了对 Quartz 的⽀持,让我们在项⽬使⽤的过程中更加的灵活简洁。
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值