Spring Boot 框架学习笔记(七)整合Quartz调度框架
- 简介
- 运行环境
- 核心概念
- 任务存储方式
- 常用API
- 使用案例
- 1. 添加依赖
- 2. 创建任务类实现`Job`接口,或者继承`QuartzJobBean`抽象类
- 实现`Job`接口
- 继承`QuartzJobBean`抽象类
- 较于`Job`接口的优点
- 3. 创建调度类调度执行
- 实现`Job`类
- 继承`QuartzJobBean`类
- 详细说明
- Job和JobDetail
- JobExecutionContext
简介
Quartz
是OpenSymphony
开源组织在Job scheduling
领域又一个开源项目,完全由Java开发,可以用来执行定时任务。Quartz
可以与J2EE和J2SE应用程序相结合也可以单独使用。
运行环境
- 嵌入独立的应用程序
- 在应用程序服务器(或servlet容器)内被实例化,参与事务
- 作为一个独立程序运行,可以通过
RMI
使用 - 可以作为独立的项目集群被实例化(负载平衡和故障转移功能),用于作业执行
核心概念
- 任务
Job
需要实现的任务类,每个
job
都必须实现org.quartz.job
接口,实现 execute() 方法,执行后完成任务。
//通过JobBulider构建一个任务实例
JobDetail jobDetail = JobBuilder.newJob(xxxJob.class);
- 触发器
Trigger
执行任务的触发器(定时),主要包含
SimpleTrigger
和CronTrigger
以及自定义Trigger
//通过TriggerBuilder构建触发器实例
SimpleTrigger trigger = TriggerBuilder.newTrigger();
- 调度器
Scheduler
任务调度器,负责基于 Trigger触发器设定的时间来执行Job任务。
//从调度工厂获取
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
任务存储方式
Quartz
提供了两种存储任务的方式:
-
Memory
:内存方式,将任务存储到内存中,当项目重启时就会丢失,不建议生产环境使用。 -
Jdbc
:数据库方式,将任务存储到Quartz
提供的固定结构的表内,项目重启任务不会丢失。
常用API
-
Scheduler
:用于定时调度程序交互的主程序接口。
Scheduler调度程序:任务执行计划表,通过
scheduler.scheduleJob
方法安排进执行任务,当到了预先定义的执行时间的时候触发trigger
,执行任务
-
Job
:可自定义的在未来某个时间能被调度程序执行的任务类 -
JobDetail
:使用JobDetail来定义定时任务的实例,JobDetail实例是通过JobBuilder类创建的 -
JobDataMap
:可以包含不限量(序列化的)的数据对象,在Job实例执行的时候,可以使用其中的数据;
JobDataMap
是Java Map
接口的一个实现,额外增加了一些便于存取基本类型数据的方法
-
Trigger
:触发器,触发执行Job任务。定义一个已被安排的任务将在什么时候执行的时间条件 -
JobBuilder
:用于声明一个任务实例,也可以定义关于该任务的详情比如任务名,组名等。通过JobBuilder声明的实例将会作为一个实际执行的任务。 -
TriggerBuilder
:触发器创建器,用于创建触发器trigger实例 -
JobListener、TriggerListener、SchedulerListener
:监听器,用于对组件的监听
使用案例
1. 添加依赖
springboot
版本2.0之后
<!--quartz依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
springboot
版本较低
<!--核心包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!--工具包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
2. 创建任务类实现Job
接口,或者继承QuartzJobBean
抽象类
实现Job
接口
/**
* 任务类
* */
public class HelloJob implements Job {
static int i = 1;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("第"+i+++"次"+"Hello,Quartz!");
}
}
继承QuartzJobBean
抽象类
/**
* 任务类
* */
public class HelloJob extends QuartzJobBean {
static int i = 1;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println("第"+i+++"次"+"Hello,Quartz!");
}
}
QuartzJobBean
是由Spring
提供,实现org.quartz.Job
接口,是对Quartz
内置任务接口的实现封装,源码如下:
public abstract class QuartzJobBean implements Job {
public QuartzJobBean() {
}
public final void execute(JobExecutionContext context) throws JobExecutionException {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValues(context.getScheduler().getContext());
pvs.addPropertyValues(context.getMergedJobDataMap());
bw.setPropertyValues(pvs, true);
} catch (SchedulerException var4) {
throw new JobExecutionException(var4);
}
this.executeInternal(context);
}
protected abstract void executeInternal(JobExecutionContext var1) throws JobExecutionException;
}
较于Job
接口的优点
- 自动将实现类实例加入IOC
使用QuartzJobBean来创建自定义任务时,Spring会自动扫描项目内的实现类,将每一个实现类通过反射机制创建出实例并将实例写入到IOC容器内。
- 可在实现类内注入实例
直接使用Quartz时,如果自定义任务类实例不加入IOC容器,我们无法在自定义任务类注入Service
3. 创建调度类调度执行
实现Job
类
/**
* 调度器
* */
public class HelloSchedulerDemo {
public static void main(String[] args) throws SchedulerException {
//1.从调度工厂获取调度器实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//2. 通过JobBulider构建一个任务实例
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
//设置任务的唯一实例名和任务组的组名
.withIdentity("helloJob","helloGroup")
//构建实例
.build();
//3. 通过TriggerBuilder构建触发器实例
SimpleTrigger trigger = TriggerBuilder.newTrigger()
//设置触发器唯一实例名和触发器组名
.withIdentity("helloTrigger","helloGroup")
//执行计划,每3秒执行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
//立即执行
.startNow()
//构建实例
.build();
//4. 调度器绑定任务实例和触发器
scheduler.scheduleJob(jobDetail,trigger);
//5.开始定时任务
scheduler.start();
}
}
继承QuartzJobBean
类
- 创建配置类
详细说明
Job和JobDetail
- JOB
Job
:工作任务调度接口,任务类需要实现的接口。该接口中定义了execute方法,类似JDK提供的
TimeTask类的
run`方法。在这里面编写任务执行的业务逻辑
Job
实例在Quartz
中的生命周期:每次调度器执行Job
时,它在调用execute
方法前会创建一个新的Job
实例,当调度完成后,管理的Job
对象实例将会被释放,释放的实例会被垃圾回收机制回收
- JobDetail
JobDetail
:作用是绑定Job
,每次Scheduler
调度执行一个Job
的时候,首先会拿到对应的Job
,然后创建该Job
实例,再去执行Job
中的execute()
的内容,任务执行结束后,关联的Job
对象实例会被释放,且会被JVM GC
清除。除此之外,JobDetail
为Job实例提供了许多设置属性
- 为什么要使用
Job+JobDetail
模式,而不是直接使用Job
JobDetail
定义任务属性,Job
定义任务逻辑
任务有可能并发执行,当直接使用Job
的时候,Job
实例可能出现并发访问的情况。
使用Job+JobDetail
模式,每次调度执行都会生成一个Job
实例,这样就不用担心并发访问的问题
JobExecutionContext
当
Scheduler
调用一个Job,就会将JobExecutionContext
传递给Job
的execute()
方法Job
能通过JobExecuteContext
对象访问到Quartz
运行时的环境以及Job
本身的明细数据