SpringBoot @Scheduled实现定时任务(附带实例)
使用 Spring Boot 内置的 @Scheduled 注解实现后台定时任务,虽然其开发简单、执行效率高,但是只适合处理简单的计划任务,不能处理分布式计划任务。在任务数量多的情况下,可能出现阻塞、延迟启动等问题。
Quartz 是 OpenSymphony 开源组织在任务调度(Job Scheduling,也称为作业调度)领域下的开源项目,它是 Java 开发的开源任务调度管理系统,具有使用灵活、配置简单的特点,能够实现复杂应用场景下的任务调度管理。
当定时任务愈加复杂时,使用 Spring Boot 注解 @Scheduled 已经不能满足业务需要。相比之下,Quartz 灵活而又不失简单,能够创建简单或复杂的调度任务,其主要具有如下功能:
Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组和名称,组和名称是 Scheduler 查找、定位容器中某个对象的依据,Trigger 的组和名称必须唯一,JobDetail 的组和名称也必须唯一(但可以与 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法,允许外部通过组和名称访问控制容器中的 Trigger 与 JobDetail。
总而言之,Scheduler 相当于一个容器,其中包含各种 Job 和 Trigger,四者之间的关系如下图所示。

图 1 四者之间的关系图
Quartz 通过 Scheduler 触发 Trigger 规则实现任务的管理和调度。除此之外,Quartz 还提供了 TriggerBuilder 和 JobBuilder 类来构建 Trigger 实例和 Job 实例。
Spring Boot 对 Quartz 做了很好的支持,它提供 spring-boot-starter-quartz 组件集成 Quartz,开箱即用,让我们在项目中使用 Quartz 变得更加简单。
示例参数说明如下:

图 2 简单任务运行日志

图 3 Cron定时任务运行日志
Quartz 是 OpenSymphony 开源组织在任务调度(Job Scheduling,也称为作业调度)领域下的开源项目,它是 Java 开发的开源任务调度管理系统,具有使用灵活、配置简单的特点,能够实现复杂应用场景下的任务调度管理。
当定时任务愈加复杂时,使用 Spring Boot 注解 @Scheduled 已经不能满足业务需要。相比之下,Quartz 灵活而又不失简单,能够创建简单或复杂的调度任务,其主要具有如下功能:
- 持久化:将任务和状态持久化到数据库;
- 任务管理:对调度任务进行有效的管理;
- 集群:借助关系数据库和 JDBC 任务存储支持集群。
SpringBoot Quartz的基本概念
想要明白 Quartz 怎么用,首先要了解 Job(任务)、JobDetail(任务信息)、Trigger(触发器)和 Scheduler(调度器)这 4 个基本概念。1) Job(任务)
接口,只有 execute(JobExecutionContext context) 方法,在实现接口的 execute() 方法中编写需要定时执行的任务,JobExecutionContext 类提供调度任务执行的上下文信息,任务运行时的信息保存在 JobDataMap 实例中。2) JobDetail(任务信息)
Quartz 每次调度任务时都重新创建一个 Job 实例,因此它不接收一个任务的实例,而是接收任务实现类(JobDetail,描述任务的实现类及其他相关的静态信息,如任务名字、描述、关联监听器等信息),以便运行时通过调用 newInstance() 方法的反射机制实例化任务。3) Trigger(触发器)
一个类,描述触发任务执行的时间触发规则,主要有 SimpleTrigger 和 CronTrigger 这两个类:- 当需要执行调度或者以固定时间间隔周期执行调度时,SimpleTrigger 是合适的选择;
- 而 CronTrigger 可以通过 Cron 表达式定义出各种复杂时间规则的调度方案,如周一到周五的 15:00~16:00 执行调度任务等。
4) Scheduler(调度器)
调度器就相当于一个容器,装载着任务和触发器,该类是一个接口,代表一个 Quartz 的独立运行容器。Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组和名称,组和名称是 Scheduler 查找、定位容器中某个对象的依据,Trigger 的组和名称必须唯一,JobDetail 的组和名称也必须唯一(但可以与 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法,允许外部通过组和名称访问控制容器中的 Trigger 与 JobDetail。
总而言之,Scheduler 相当于一个容器,其中包含各种 Job 和 Trigger,四者之间的关系如下图所示。

图 1 四者之间的关系图
Quartz 通过 Scheduler 触发 Trigger 规则实现任务的管理和调度。除此之外,Quartz 还提供了 TriggerBuilder 和 JobBuilder 类来构建 Trigger 实例和 Job 实例。
Spring Boot 对 Quartz 做了很好的支持,它提供 spring-boot-starter-quartz 组件集成 Quartz,开箱即用,让我们在项目中使用 Quartz 变得更加简单。
SpringBoot简单定时任务
Quartz 主要有简单定时调度器(SimpleSchedule)和 Cron表达式调度器(CronSchedule)来调度触发的定时任务。下面通过示例演示这两种调度器的用法。1) 添加Quartz依赖
在 pom.xml 中配置 Quartz 的依赖包 spring-boot-starter-quartz,具体配置如下:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
2) 创建任务
创建定时任务的实现类 SampleJob,并继承 QuartzJobBean,示例代码如下:public class SampleJob extends QuartzJobBean { private static final Logger logger = LoggerFactory.getLogger(SchedulerTask.class); private String name; public void setName(String name) { this.name = name; } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { logger.info(String.format("Hello %s!", this.name)); } }在上面的示例中,SampleJob 实现了 executeInternal() 方法执行后台任务,同时定义的 Name 变量用于触发任务时传入参数。
3) 构建JobDetail、CronTrigger
接下来构建 JobDetail 和 Trigger 实例。首先使用 SimpleScheduleBuilder 创建 Scheduler 实例,然后关联 JobDetail 和 Trigger 实例。示例代码如下:@Configuration public class SampleScheduler { @Bean public JobDetail sampleJobDetail() { return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob") .usingJobData("name", "weiz test1") .storeDurably() .build(); } @Bean public Trigger sampleJobTrigger() { SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(10).repeatForever(); return TriggerBuilder .newTrigger() .forJob(sampleJobDetail()) .withIdentity("sampleTrigger") .withSchedule(scheduleBuilder).build(); } }在上面的示例中,定义的 SampleScheduler 调度器类包含 JobDetail 和 Trigger 两个对象,分别用于控制任务启动时的参数传入和任务触发规则。
示例参数说明如下:
- JobBuilder 类构造函数只能通过 JobBuilder 的静态方法 newJob(Class<? extends Job> jobClass) 生成 JobDetail 实例;
- usingJobData() 方法动态传入 Job 任务中的参数,这里传入 SampleJob 任务类中的 name 参数;
- withIdentity() 方法可以传入 String name 和 String group 两个参数来定义 TriggerKey。当然,也可以不设置参数,Quartz 会自动生成一个独一无二的 TriggerKey 来区分不同的触发器;
- withIntervalInSeconds() 方法中的任务触发规则包含 withIntervalInXXX 等多种时间设置。示例代码中定义了每 10 秒执行一次任务。
4) 运行任务
启动项目,验证任务是否能正常运行。如下图所示,SampleJob 后台任务成功运行,每隔 10 秒执行一次,这说明使用 SimpleSchedule 创建简单的定时任务运行成功。
图 2 简单任务运行日志
SpringBoot Cron定时任务
如果需要定义更复杂的应用场景可以使用 CronSchedule,它可以设置更灵活的使用方式,定时设置可以参考上面的 Cron 表达式。其实两种定时任务大体一致,只是 SimpleSchedule 换成了 CronSchedule。1) 定义Job
public class CronJob extends QuartzJobBean { private static final Logger logger = LoggerFactory.getLogger(SchedulerTask.class); private String name; public void setName(String name) { this.name = name; } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { logger.info(String.format("Hello %s!", this.name)); } }在上面的示例中,定义 CronJob 后台任务,继承自 QuartzJobBean 类,然后实现 executeInternal() 方法,与之前的任务一样。
2) 构建JobDetail、CronTrigger
使用 Scheduler 关联 JobDetail 和 CronTrigger,并设置每隔 10 秒执行一次。@Configuration public class CronScheduler { @Bean public JobDetail cronJobDetail(){ return JobBuilder.newJob(CronJob.class) .withIdentity("cronJob") .usingJobData("name","weiz cronJob") .storeDurably() .build(); } @Bean public Trigger cronJobTrigger(){ CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?"); return TriggerBuilder.newTrigger() .withIdentity("CronSchedule") .forJob(cronJobDetail()) .withSchedule(scheduleBuilder) .build(); } }在上面的示例中,也是创建 JobDetail 和 JobTrigger,不同的是,这里使用 CronScheduleBuilder 创建调度器,传入“0/10 * * * * ?”Cron表达式,设置任务每隔 10 秒执行一次。
3) 运行任务
启动项目,验证任务是否能正常运行,如下图所示,CronJob 后台任务成功运行,每隔 10 秒执行一次。这说明使用 CronSchedule 创建复杂的 Cron 定时任务运行成功。
图 3 Cron定时任务运行日志
相关文章
- SpringBoot @Scheduled定时任务详解(附带实例)
- SpringBoot是什么?SpringBoot的优缺点有哪些?
- SpringBoot URL映射详解(附带实例)
- SpringBoot @PathVariable实现参数传递(附带实例)
- SpringBoot传递参数的5种方法(附带实例)
- SpringBoot Cron表达式的用法(新手必看)
- SpringBoot集成Redis详解(附带实例)
- SpringBoot集成RabbitMQ详解(附带实例)
- SpringBoot实现RabbitMQ简单队列(附带实例)
- SpringBoot是什么,SpringBoot简介(新手必看)