Quartz官网
http://www.quartz-scheduler.org/
特点
- 强大的调度功能
- 灵活的应用方式
- 分布式和集群能力
主要用到的设计模式
- Builder 模式
- Factory 模式
- 组件模式
- 链式写法
三个核心概念
- 调度器
- 任务
- 触发器
Quartz 体系结构
JobDetail
scheduler
trigger
-SimpleTrigger
-CronTrigger
重要组成
Job
JobDetail
JobBuilder
JobStore
Trigger
TriggerBuilder
ThreadPool
Scheduler
Calendar
监听器
JobListener
TriggerListener
SchedulerListener
Quartz 实例
依赖
org.quartz-scheduler
quartz
2.3.2
org.slf4j
slf4j-simple
1.7.25
compile
定义任务 MyJob.java
package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateFormat.format(new Date()));
}
}
调度任务 QuartzDemo.java
package timer;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzDemo {
public static void main(String[] args) throws SchedulerException {
// 创建JobDetail
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever();
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(scheduleBuilder)
.build();
// 通过工厂方法创建Scheduler实例
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
Job 和 JobDetail
1、Job 源码:
package org.quartz;
public interface Job {
void execute(JobExecutionContext context)
throws JobExecutionException;
}
2、Job 的生命周期:
每次调度器执行 Job 时,调用 execute 方法前会创建一个新的 Job 实例 调用完成后,关联的 Job 对象实例会被释放,释放的实例会被垃圾回收机制回收
3、JobDetail:
JobDetail 为 Job 实例提供了许多设置属性,以及 JobDataMap 成员变量属性, 它用来存储特定 Job 实例的状态信息,调度器需要借助 JobDetail 对象来添加 Job 实例
4、JobDetail 重要属性
name
group 默认值DEFAULT
jobClass
jobDataMap
// 创建JobDetail
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 打印jobDetail属性
System.out.println(jobDetail.getKey().getName()); // myJob
System.out.println(jobDetail.getKey().getGroup()); // group1
System.out.println(jobDetail.getJobClass().getName()); // timer.MyJob
JobExecutionContext & JobDataMap
1、JobExecutionContext:
Scheduler 给 Job 传递参数
2、JobDataMap:
可以装载任何可序列化的数据对象 实现了 Map 接口
设置 JobDataMap 部分代码
// 创建JobDetail
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.usingJobData("name", "jobDetail")
.build();
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever();
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.usingJobData("name", "trigger")
.withSchedule(scheduleBuilder)
.build();
获取 JobDataMap
方法一:直接从 JobDataMap 对象中获取
package timer;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 获取 jobkey
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
System.out.println(jobKey.getName()); // myJob
System.out.println(jobKey.getGroup()); // group1
// 获取JobDetail的DataMap
JobDataMap jobDetailDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println(jobDetailDataMap.getString("name"));
// jobDetail
// 获取Trigger的DataMap
JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
System.out.println(triggerDataMap.getString("name"));
// trigger
// 获取合并后的DataMap
JobDataMap dataMap = jobExecutionContext.getMergedJobDataMap();
System.out.println(dataMap.getString("name"));
// trigger
}
}
方法二:定义同名变量获取
package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println(this.name);
}
}
Trigger
Trigger 是触发器,用来告诉调度程序作业什么时候触发
触发器通用属性
JobKey: Job 实例的标识,触发器被触发时,指定的 job 实例会执行
StartTime:触发器的时间表首次被触发的时间,类型是 Java.util.Date
EndTime:触发器不再被触发的时间 Java.util.Date
设置部分代码
// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 获取6秒后的时间
Date endDate = new Date();
endDate.setTime(endDate.getTime() + 3000);
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate)
.endAt(endDate)
.usingJobData("name", "trigger")
.withSchedule(scheduleBuilder)
.build();
Job 中获取 Trigger 数据
package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Trigger;
import java.text.SimpleDateFormat;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Trigger trigger = jobExecutionContext.getTrigger();
// 获取开始时间和结束时间
System.out.println(dateFormat.format(trigger.getStartTime()));
System.out.println(dateFormat.format(trigger.getEndTime()));
// 获取JobKey
System.out.println(trigger.getJobKey().getName());
System.out.println(trigger.getJobKey().getGroup());
}
}
SimpleTrigger
指定时间段内执行一次作业任务 或者在指定的时间间隔内多次执行作业任务
任务
package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateFormat.format(new Date()));
}
}
示例 1
// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 3秒钟之后执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate)
.build();
示例 2
// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.withRepeatCount(3);
// 3s之后执行第一次,之后每隔2s执行一次,重复3次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate)
.withSchedule(scheduleBuilder)
.build();
示例 3
// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000L);
// 获取6秒后的时间
Date endDate = new Date();
endDate.setTime(endDate.getTime() + 6000L);
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.withRepeatCount(3);
// 3s之后执行第一次,之后每隔2s执行一次,6秒之后结束
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate)
.endAt(endDate)
.withSchedule(scheduleBuilder)
.build();
注意:
- 重复次数可以为 0、正整数、SimpleTrigger.REPEAT_INDEFINITELY
- 重复执行间隔必须为 0 或长整数
- 一旦执行了 endTime 参数,那么会覆盖重复次数参数的效果
基于日历的作业调度器,而不是像 SimpleTrigger 那样精确指定时间间隔,较为常用
格式:
秒 分 时 日 月 周 年
特殊符号说明
, 或 10,12
- 区间 10-12
/ 每 */5
* 所有值 *
? 不指定
提示
- L 和 W 可以组合使用
- 周字段不区分大小写 mon 与 MON 相同
- 利用在线生成工具
示例
// 每2秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ? *"))
.build();
Scheduler
StdSchedulerFactory
配置参数一般存储在 quartz.properties
主要函数
// 将job和trigger注册到scheduler
Date scheduleJob(JobDetail jobDetail, Trigger trigger)
// 启动
void start()
// 暂停
void standby()
// 关闭
// true 等待所有任务执行完成再关闭
// false 直接关闭
void shutdown()
quartz.properties
文档位置和加载顺序
jar 包下有默认配置
组成部分
- 调度器属性
- 线程池属性
- 作业存储位置
- 插件配置
新建 maven webapp
依赖
webmvc
context
aop
core
配置 Quartz 的两种方式:
- MethodInvokingJobDetailFactoryBean 适合调用特定 bean 方法时很方便
- JobDetailFactoryBean 支持传入一些参数
项目结构
$ tree -I target
.
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── mouday
│ │ ├── controller
│ │ │ └── IndexController.java
│ │ └── quartz
│ │ ├── ComplexJob.java
│ │ └── SimpleJob.java
│ ├── resources
│ │ └── dispatcher-servlet.xml
│ └── webapp
│ ├── WEB-INF
│ │ └── web.xml
│ └── index.jsp
1、pom.xml
4.0.0
org.example
spring-mvc-demo
1.0-SNAPSHOT
UTF-8
5.2.6.RELEASE
springquartz
org.apache.tomcat.maven
tomcat7-maven-plugin
2.2
8080
/
UTF-8
true
src/main/webapp/WEB-INF/web.xml
true
org.springframework
spring-core
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-expression
${spring.version}
commons-logging
commons-logging
1.2
javax.servlet
javax.servlet-api
4.0.1
provided
jstl
jstl
1.2
org.quartz-scheduler
quartz
2.3.2
org.slf4j
slf4j-simple
1.7.25
compile
2、src/main/webapp/index.jsp
Hello World!
3、src/main/webapp/WEB-INF/web.xml
dispatcher
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:dispatcher-servlet.xml
1
dispatcher
/
index.jsp
4、src/main/resources/dispatcher-servlet.xml
text/html; charset=utf-8
5、src/main/java/com/mouday/controller/IndexController.java
package com.mouday.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 仅用于SpringMVC服务测试
*/
@Controller
public class IndexController {
@GetMapping("/login")
@ResponseBody
public String login(
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "password", required = false) String password
) {
return "name:" + name + " password:" + password;
}
}
6、src/main/java/com/mouday/quartz/SimpleJob.java
package com.mouday.quartz;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component("simpleJob")
public class SimpleJob {
public void sayHello(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("SimpleJob "+ dateFormat.format(new Date()) );
}
}
7、src/main/java/com/mouday/quartz/ComplexJob.java
package com.mouday.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ComplexJob extends QuartzJobBean {
private String name;
public void setName(String name) {
this.name = name;
}
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("ComplexJob name: " + this.name + " " + dateFormat.format(new Date()));
}
}
总结
- Timer 优缺点
- Quartz 三大要素
- Quartz&Spring 融合