Quartz作业调度框架(附整合Spring)
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.0。
1. 结构
Quartz是一个完全由java编写的开源作业调度框架。不要让作业调度这个术语吓着你。尽管Quartz框架整合了许多额外功能, 但就其简易形式看,你会发现它易用得简直让人受不了!。简单地创建一个实现org.quartz.Job接口的java类。Job接口包含唯一的方法:
public void execute(JobExecutionContext context)
throws JobExecutionException;
在你的Job接口实现类里面,添加一些逻辑到execute()方法。一旦你配置好Job实现类并设定好调度时间表,Quartz将密切注意剩余时间。当调度程序确定该是通知你的作业的时候,Quartz框架将调用你Job实现类(作业类)上的execute()方法并允许做它该做的事情。无需报告任何东西给调度器或调用任何特定的东西。仅仅执行任务和结束任务即可。如果配置你的作业在随后再次被调用,Quartz框架将在恰当的时间再次调用它。
1. 框架特征
编辑
Quartz框架有一个丰富的特征集。事实上,Quartz有太多特性以致不能在一种情况中全部领会,下面列出了一些有意思的特征,但没时间在此详细讨论。
监听器和插件
每个人都喜欢监听和插件。今天,几乎下载任何开源框架,你必定会发现支持这两个概念。监听是你创建的java类,当关键事件发生时会收到框架的回调。例如,当一个作业被调度、没有调度或触发器终止和不再触发时,这些都可以通过设置来通知你的监听器。Quartz框架包含了调度器监听、作业和触发器监听。你可以配置作业和触发器监听为全局监听或者是特定于作业和触发器的监听。
一旦你的一个具体监听被调用,你就能使用这个技术来做一些你想要在监听类里面做的事情。例如,你如果想要在每次作业完成时发送一个电子邮件,你可以将这个逻辑写进作业里面,也可以写进JobListener里面。写进JobListener的方式强制使用松耦合有利于设计上做到更好。
Quartz插件是一个新的功能特性,无须修改Quartz源码便可被创建和添加进Quartz框架。他为想要扩展Quartz框架又没有时间提交改变给Quartz开发团队和等待新版本的开发人员而设计。如果你熟悉Struts插件的话,那么完全可以理解Quartz插件的使用。
与其Quartz提供一个不能满足你需要的有限扩展点,还不如通过使用插件来拥有可修整的扩展点。
集群Quartz应用
Quartz应用能被集群,是水平集群还是垂直集群取决于你自己的需要。集群提供以下好处:
·伸缩性
·高可用性
·负载均衡
Quartz可以借助关系数据库和JDBC作业存储支持集群。
Terracotta扩展quartz提供集群功能而不需要数据库支持
相关工具
Quartz经常会用到cron表达式,可以使用国外网站cronmaker辅助生成cron表达式。
1. 核心接口和类
1) Scheduler接口
它提供了对作业计划的启动、停止、恢复、删除、对作业计划的重新定制的方法
它通过JobDetail和trigger创建一个作业计划
2) Job接口
只需要实现一个方法void execute(JobExecutionContext context)
程序中需要被执行的作业就需要在execute中实现。
3) JobDetail类
通过JobDetail类可以设置具体执行的Job,并且给执行的Job设置名称,组,描述等信息,该类包括一个JobDetail(String name,String group,Class JobClass)构造器,它的参数
分别是job的名称,组名,和实现了job接口的实现类
4) Trigger类
主要是设置触发Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger这两个子类。
SimpleTrigger擅长执行单次执行或者固定周期计划任务执行。
CronTrigger则可以通过Cron表达式定义出各种复杂的时间规则的调度方案。
1. Cron表达式
语法为 秒 分 时 日 月 年(可省略)
1. Cron表达式训练
(1) */5 ** ** ? --每隔5秒执行一次
(2) 0 */1 *** ? –每隔1分钟执行一次
(3) 00 23 ** ? – 每天23点执行一次
(4) 00 1? ** --每周日凌晨1点执行一次
(5) 00 11 *? 每月1号凌晨1点执行一次
(6) 0 26,29,33 ***? 在26分,29分,33分执行一次
1. Spring整合QuartZ框架
一个普通的java类,配置JobDetail,Trigger,Scheduler
1. 依赖的jar包
Spring-context-support.jar
Spring-tx.jar
Quartz.jar
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
1. 搭建项目
3. 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<context:component-scan base-package="com.cxl.scheduler"/>
<bean id="myJob" class="com.cxl.scheduler.MyJob"/>
<!--指定需要定时运行的方法-->
<bean id="myJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJob"/>
<property name="targetMethod" value="mockCallService"/>
</bean>
<!--按指定频率执行-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="myJobDetail"/>
<!--启动延时-->
<property name="startDelay" value="0"></property>
<!--执行评率,单位,毫秒-->
<property name="repeatInterval" value="2000"/>
</bean>
<!--
<!–按指定时间执行–>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJobDetail"/>
<property name="cronExpression" value="0 26,27 16 * * ?"/>
</bean>-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
<!--<ref bean="cronTrigger"/>-->
</list>
</property>
</bean>
4. 运行项目(以simpleTrigger来启动)
可以发现,它是每2秒使用这个方法一次
按是制定时间来运行
1. QuartZ工具类
.
import static org.quartz.JobBuilder.newJob;
import static org.quartz.JobKey.jobKey;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.TriggerKey.triggerKey;
import java.util.Date;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
public class QuartzUtils {
private static String JOB_NAME = "EXTJWEB_NAME";
private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";
private static String TRIGGER_NAME = "EXTJWEB_NAME";
private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";
/**
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @param sched:调度器
* @param jobClass:任务
* @param time:时间设置,CronExpression表达式
*/
public static void addJob(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time) {
addJob(sched, jobClass,time,JOB_NAME,JOB_GROUP_NAME,TRIGGER_NAME,TRIGGER_GROUP_NAME);
}
/**
* @Description: 添加一个定时任务
* @param sched:调度器
* @param jobClass:任务
* @param time:时间设置,CronExpression表达式
* @param jobName:任务名
* @param jobGroupName:任务组名
* @param triggerName:触发器名
* @param triggerGroupName:触发器组名
*/
public static void addJob(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
JobDetail job = newJob(jobClass).withIdentity(jobName, jobGroupName).build();
CronTrigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName)
.withSchedule(cronSchedule(time)).build();
try {
// 返回为 null 添加失败
Date ft = sched.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 定义一个任务之后进行触发设定(使用默认的任务组名,触发器名,触发器组名)
* @param sched:调度器
* @param time
*/
@SuppressWarnings("rawtypes")
public static void addJObLaterUse(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time) {
addJObLaterUse(sched,jobClass,time,JOB_NAME,JOB_GROUP_NAME);
}
/**
* @Description: 定义一个任务之后进行触发设定
* @param sched:调度器
* @param time
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
@SuppressWarnings("rawtypes")
public static void addJObLaterUse(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName,String jobGroupName) {
JobDetail job = newJob(jobClass).withIdentity(jobName, jobGroupName).storeDurably().build();
try {
sched.addJob(job, false);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 对已存储的任务进行scheduling(使用默认的任务组名,触发器名,触发器组名)
* @param sched:调度器
* @param time
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
@SuppressWarnings("rawtypes")
public static void schedulingStoredJOb(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time) {
schedulingStoredJOb(sched,jobClass,time,JOB_NAME,JOB_GROUP_NAME,TRIGGER_NAME,TRIGGER_GROUP_NAME);
}
/**
* @Description: 对已存储的任务进行scheduling
* @param sched:调度器
* @param time
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
@SuppressWarnings("rawtypes")
public static void schedulingStoredJOb(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName,String jobGroupName,String triggerName, String triggerGroupName) {
Trigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName).startNow()
.forJob(jobKey(jobName,jobGroupName))
.build();
try {
sched.scheduleJob(trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
* @param sched:调度器
* @param time
*/
@SuppressWarnings("rawtypes")
public static void modifyJobTime(Scheduler sched, String time) {
modifyJobTime(sched, TRIGGER_NAME, TRIGGER_GROUP_NAME, time);
}
/**
* @Description: 修改一个任务的触发时间
* @param sched:调度器
* @param triggerName
* @param triggerGroupName
* @param time
*/
public static void modifyJobTime(Scheduler sched, String triggerName, String triggerGroupName, String time) {
Trigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName).withSchedule(cronSchedule(time)).startNow().build();
try {
sched.rescheduleJob(triggerKey(triggerName, triggerGroupName), trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 修改一个任务(使用默认的任务组名,任务名)
* @param sched:调度器
*/
@SuppressWarnings("rawtypes")
public static void modifyJob(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass) {
modifyJob(sched,jobClass,JOB_NAME,JOB_GROUP_NAME);
}
/**
* @Description: 修改一个任务
* @param sched:调度器
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
public static void modifyJob(Scheduler sched, @SuppressWarnings("rawtypes") Class jobClass, String jobName,String jobGroupName) {
JobDetail job1 = newJob(jobClass).withIdentity(jobName,jobGroupName).build();
try {
sched.addJob(job1, true);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 删除一个任务的的trigger
* @param sched:调度器
* @param triggerName
* @param triggerGroupName
*/
public static void unschedulingJob(Scheduler sched,String triggerName, String triggerGroupName) {
try {
sched.unscheduleJob(triggerKey(triggerName,triggerGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 移除一个任务,以及任务的所有trigger
* @param sched:调度器
* @param jobName
*/
public static void removeJob(Scheduler sched, String jobName,String jobGroupName) {
try {
sched.deleteJob(jobKey(jobName,jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:启动所有定时任务
* @param sched:调度器
*/
public static void startJobs(Scheduler sched) {
try {
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
* @param sched:调度器
*/
public static void shutdownJobs(Scheduler sched) {
try {
if (!sched.isShutdown()) {
//未传参或false:不等待执行完成便结束;true:等待任务执行完才结束
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}