文章目录
参考资料: 视频资料
一、Quartz
Quartz 官网:scheduler.org
Quartz 是 OpenSymphon 开源组织发布的开源项目,可以和J2EE 和 J2SE 应用程序相结合,也可以单独使用。
Quartz 是开源且具有丰富特性的“任务调度库”,能够集成任何的Java应用,小到独立的应用,大到电子商业系统。Quartz既能创建简单,也能创建复杂的任务调度,以执行上十、上百,甚至上万的任务。任务 job 被定义为标准的Java组件,能够执行任何想要实现的功能。
Quartz 调度框架包含许多企业级的任务如 JTA 事务、 集群的支持。
简而言之,Quartz 就是基于Java实现的任务调度框架,用于执行自定义的任务。
二、Quartz 运行环境
- Quartz 可以运行嵌入在另一个独立式应用程序
- Quartz 可以在应用程序服务器(或Servlet容器)内被实例化,并且参与事务
- Quartz 可以作为一个独立的程序运行(其自己的Java虚拟机内),可以通过RMI使用
- Quartz 可以被实例化,作为独立的项目集群(负载均衡和故障转移功能),用于作业的执行
三、Quartz 核心组件
- 任务 Job
- Job 就是想要实现的任务类,每一个 Job 必须实现 org.quartz.job接口, 且只需要实现接口定义的 execute()方法
- 触发器 Trigger
- Trigger 为你执行任务的触发器,,比如每天定时3点发送一份统计邮件, Trigger将会设置3点进行执行该任务。
- Trigger主要包含两种 SimpleTrigger 和 CronTrigger 两种
- 调度器 Scheduler
- Scheduler 为任务的调度器,它会将任务 Job 以及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行Job
四、Quartz 设计模式
-
Builder 模式
官方案例中使用 newJob(字节码).withXXX.build()的方式创建工作
-
Factory 模式
官方案例中通过 StdSchedulerFactory类获取 调度器对象
-
组件模式
Job、Trigger触发器 和 Scheduler调度器三个组件
-
链式编程
Quartz的类其中部分方法返回的结果就是当前对象实例,所以可以支持链式编程
五、Quartz 的体系结构
六、Quartz 的几个常用 API
以下是 Quartz 编程 API 的几个重要接口,也是 Quartz 的重要组件:
- Scheduler 是用于与调度程序交互的主程序接口
Scheduler 调度程序,任务执行计划表,只有安排进执行计划的任务 job (通过 scheduler.schedulerJob方法安排进执行计划),当它预先定义的执行时间到了的时候(任务触发 Trigger),该任务才会执行。
-
Job 我们预先定义的希望在未来时间能被调度程序执行的时候,可以自定义。
-
JobDetail ,使用 jobDetail来定义定时任务的实例通过 ,JobBuilder类创建
-
JobDataMap,可以包含不限量(序列化的)数据对象,在 job 实例执行的时候,可以使用其中的数据; JobDataMap 是 Java Map接口的一个实现,额外增加了一些便于存取基本类型数据的方法。
-
Trigger 触发器,Trigger对象是用来执行Job的。当调度一个 Job 时,我们实例一个触发器会调整它的属性来满足 job 执行的条件。表明任务在什么时候会执行,定义了一个已被安排的任务将会在什么时候执行的条件,比如每2秒执行一次
-
JobBuilder 用于声明一个任务实例,也可以定义关于该任务的详情,比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。
-
TriggerBuilder 触发器创建器,用于创建触发器 trigger 实例
-
JobListener、TriggerListener、SchedulerLisener 监听器,用于对组件的监听。
七、Quartz 入门案例
项目结构:
引入Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>quartzDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
</project>
自定义Job
package cn.uni.job;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* 自定义 Quartz 框架里的任务
*/
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 获取当前时间
String t = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
// 工作内容
System.out.printf("[%s] 工作中...\n", t);
}
}
定义 Scheduler、Trigger与测试
package cn.uni.main;
import cn.uni.job.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class HelloSchedulerDemo {
public static void main(String[] args) {
try {
// 1. 调度器 ( Scheduler ) 从工厂中获取调度的实例 (默认: 实例化 new StdSchedulerFactory())
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2. 任务实例 ( JobDetail )
JobDetail jobDetail = JobBuilder.newJob(MyJob.class) // 加载任务类, 与自定义的Job类进行绑定
// 参数1: 任务的名称 (唯一实例), 参数2:任务组名称
.withIdentity("job1", "jobGroup1")
.build();
// 3. 触发器 (Trigger)
SimpleTrigger trigger = TriggerBuilder.newTrigger()
// 参数1: 触发器的名称(唯一实例),参数2:触发器组的名称
.withIdentity("trigger1", "triggerGroup1")
// 设置每过 3 秒执行一次
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
// 设置立马启动
.startNow()
.build();
// 让调度器关联任务和触发器, 保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail, trigger);
// 启动调度器
scheduler.start();
// 停止调度器
// scheduler.shutdown();
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
}
运行结果(每隔三秒执行一次自定义的Job):
[2022-07-08 11:23:09] 工作中...
[2022-07-08 11:23:12] 工作中...
[2022-07-08 11:23:15] 工作中...
八、Quartz组件详情
8.1 Job
Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义 execute()方法,类似JDK提供的 TimeTask 类的run方法,在里面编写任务执行的业务逻辑
Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例,当调用完成后,关联的Job对象实例会被释放,释放的实例将会被垃圾回收机制回收。
比如在入门案例七的基础上修改Job类如下:
package cn.uni.job;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* 自定义 Quartz 框架里的任务
*/
public class MyJob implements Job {
public MyJob(){
System.out.println("hello, job!");
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 获取当前时间
String t = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
// 工作内容
System.out.printf("[%s] 工作中...\n", t);
}
}
运行结果:
hello, job!
[2022-07-08 12:34:38] 工作中...
hello, job!
[2022-07-08 12:34:41] 工作中...
从这里可以看出,Job类每次执行前都被重新定义过。
8.2 JobDetail
JobDetail为Job实例提供了许多设置属性,以及 JobDataMap成员变量属性,它用来存储特定 job 实例的状态信息,调度器需要借助 jobDetail 对象来添加 job 实例。
JobDetail jobDetail = JobBuilder.newJob(MyJob.class) // 加载任务类, 与自定义的Job类进行绑定
// 参数1: 任务的名称 (唯一实例), 参数2:任务组名称
.withIdentity("job1", "jobGroup1")
.build();
System.out.println(