Quartz概念
Quartz是openSymphony开源组织在Job scheduling领域的开源项目,它可以与J2EE与J2SE应用程序相结合,也可以单独使用。
Quartz是开源且具有丰富特性的“任务调度库”,能够集成于任何的Java应用,小到独立的应用,大到电子商业系统。Quartz能够创建亦简单亦复杂的调度,以执行上百、千,甚至上万的任务。任务job被定义为标准的Java组件,能够执行任何你想要实现的功能。
官网:http://www.quartz-scheduler.org/
Quartz运行环境
Quartz可以运行嵌入在另一个独立式应用程序
Quartz可以在应用程序服务器(或servlet容器)内被实例化,并且参与事务
Quartz可以作为一个独立的程序运行(其自己的Java虚拟机内),可以通过RMI使用
Quartz可以被实例化,作为独立的项目集群(负载均衡和故障转移功能),用于作业的执行
Quartz设计模式
Builder模式
Factory模式
组件模式
链式模式
Quartz的核心概念
1、任务job
Job就是你想要实现的任务类,每一个Job必须实现org.quartz.job接口,且只需要实现接口定义的execute()方法。
2、触发器Trigger
Trigger为你执行任务的触发器。不如说每天定时3点发送一份统计邮件,Trigger将会设置3点进行执行该任务。
Trigger主要包含两种: SimpleTrigger 和 CronTrigger两种。
3、调度器Scheduler
Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job。
Quartz的体系结构
Quartz的几个常用API
以下是Quartz编程API几个重要接口,也是Quartz的重要组件
1、Scheduler
用于与调度程序交互的主程序接口
Scheduler调度程序通过任务执行计划表,只有安排进执行计划的任务Job(通过scheduler.scheduleJob方法安排进执行计划),当它预先定义的执行时间到了的时候(任务触发trigger),该任务才会执行。
2、Job
我们预先定义的希望在未来时间能够被调度程序执行的任务类,我们可以自定义
3、JobDetail
使用JobDetail来定义定时任务的实例,JobDetail实例通过JobBuilder类创建的。
4、JobDataMap
可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法。
5、Trigger触发器
Trigger对象是用来触发执行job的。当调度一个job时,我们实例一个触发器然后调整它的属性来满足job执行的条件。表明任务在什么时候会执行。定义了一个已经被安排的任务将会在什么时候执行的时间条件,比方说每两秒钟执行一次。
6、JobBuilder
用于声明一个任务实例,也可以定义关于该任务的详情,比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。
7、TriggerBuilder
触发器创建器,用于创建触发器trigger实例
8、JobListener、TriggerListener、SchedulerListener监听器,用于对组件的监听
Quartz的使用
入门案例
新建maven项目,导入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
创建HelloJob任务类
package com.affection.quartz.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 邢道荣
* @date 2022/12/9 14:25
*/
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 输出当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(date);
// 工作内容
System.out.println("数据库正在进行备份,备份时间是:" + dateString);
}
}
然后创建任务调度类HelloSchedulerDemo
package com.affection.quartz.job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
* @author 邢道荣
* @date 2022/12/9 14:30
*/
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1、调度器(Scheduler)
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") //参数1: 任务的名称(唯一实例); 参数二: 任务组的名称
.build();
// 3、触发器(Trigger)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例); 参数2:触发器组的名称
.startNow() // 马上启动触发器
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
.build();
// 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}
Job与JobDetail介绍
Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义了execute方法,类似于JDK提供的TimeTask类的run方法。在里面编写任务执行的业务逻辑。
Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新的job实例,当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收。
JobDetail: JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。
JobDetail重要属性:name、group、jobClass、JobDataMap
JobExecutionContext介绍
当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 输出当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(date);
// 工作内容
System.out.println("数据库正在进行备份,备份时间是:" + dateString);
JobKey jobKey = context.getJobDetail().getKey();
System.out.println("工作任务名称:" + jobKey.getName() + "; 工作任务的组:" + jobKey.getGroup());
System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getSimpleName());
}
}
JobDataMap介绍
(1)、使用Map获取。
在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取。
JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它。
JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 输出当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(date);
// 工作内容
System.out.println("数据库正在进行备份,备份时间是:" + dateString);
JobKey jobKey = context.getJobDetail().getKey();
System.out.println("工作任务名称:" + jobKey.getName() + "; 工作任务的组:" + jobKey.getGroup());
System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getName());
System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getSimpleName());
// 从JobDetail对象中获取JobDataMap的数据
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String message = jobDataMap.getString("message");
System.out.println("任务数据的参数值:" + message);
// 获取Trigger对象中获取jobDataMap的数据
JobDataMap jobDataMapTrigger = context.getTrigger().getJobDataMap();
String messageTriagger = jobDataMapTrigger.getString("message");
System.out.println("触发器数据的参数值:" + messageTriagger);
// 获取Trigger的内容
TriggerKey triggerKey = context.getTrigger().getKey();
System.out.println("触发器名称:" + triggerKey.getName() + " ; 触发器组: " + triggerKey.getGroup());
}
}
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1、调度器(Scheduler)
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") //参数1: 任务的名称(唯一实例); 参数二: 任务组的名称
.usingJobData("message", "打印日志") // 传递参数,名称message
.build();
// 3、触发器(Trigger)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例); 参数2:触发器组的名称
.startNow() // 马上启动触发器
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
.usingJobData("message", "simple触发器") // 传递参数,名称 message
.build();
// 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}
(2)、Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动地调用这些setter方法。
public class HelloJob implements Job {
private String message;
public void setMessage(String message) {
this.message = message;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(message);
}
}
如果遇到同名的key,Trigger中的usingJobData会覆盖JobDetail中的usingJobData。
有状态的Job与无状态的Job
@PersistJobDataAfterExecution注解的使用
有状态的Job可以理解为多次调用Job期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态job每次调用时都会创建一个新的JobDataMap。
@PersistJobDataAfterExecution // 多次调用Job的时候,会对Job进行持久化,即保存一个数据的信息
public class HelloJob implements Job {
private Integer count;
public void setCount(Integer count) {
this.count = count;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 累加count
++count;
// 将count存放到JobDataMap中
context.getJobDetail().getJobDataMap().put("count", count);
System.out.println("count的数量:" + count);
}
}