Quartz介绍
Quartz是一个开源的任务调度系统,在实际的项目开发中需要很多调度任务来完成业务。为在项目更好应用,调试我们需要了解它主要结构,及特征。
运行特征
- 很容易集成到应用程序中,spring有很好支持。
- 支持各种cronExpression表达式定制触发器。
- 可以将任务持久化到数据库,并支持集群。
主要对象
- Job表示一个工作,要执行的具体内容。此接口中只有一个方法
void execute(JobExecutionContext context) - JobDetail JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。
- Trigger代表一个调度参数的配置,什么时候去调。
- Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。
通过如下代码例子来理解它们关系(quartz-2.2.1.jar):
public class quartzTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// 3、创建Scheduler对象,并配置JobDetail和Trigger对象
DirectSchedulerFactory schedulerFactory = DirectSchedulerFactory.getInstance();
schedulerFactory.createVolatileScheduler(2);
Scheduler scheduler = schedulerFactory.getScheduler();
buildScheduler(scheduler);
// 开启容器
scheduler.start();
// 查询容器中job
showJobTask(scheduler);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showJobTask(Scheduler scheduler) throws SchedulerException {
List<String> jobGroupNames = scheduler.getJobGroupNames();
for (String jobGroupName : jobGroupNames) {
// scheduler.get
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroupName));
for (JobKey jobKey : jobKeys) {
JobDetail JobDetail = scheduler.getJobDetail(jobKey);
System.out.println(JobDetail.getDescription() + "cccc" + jobKeys.toString());
}
}
}
public static void buildScheduler(Scheduler scheduler) throws SchedulerException {
// 创建一个JobDetail
JobDetail jobDetail = new JobDetailImpl("andreTaskName", "group1", TestTask.class);
// 创建一个Trigger触发器
SimpleTriggerImpl trigger = new SimpleTriggerImpl();
trigger.setJobGroup("jobGroup");
trigger.setName("trigger_one");
trigger.setStartTime(new Date());
// trigger.setEndTime(endTime);
// 设置重复间隔时间 2s
trigger.setRepeatInterval(2000L);
trigger.setRepeatCount(3);
// 添加到相应的scheduler容器中
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 具体job任务
*
* @author my
* @Date 2016年7月14日 下午3:47:57
*/
public static class TestTask implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("System executing something." + new Date());
}
}
}
总结
- scheduler是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。
- JobDetail是一个可执行的工作,它本身可能是有状态的。对应数据表qrtz_job_details
- Trigger代表一个调度参数的配置,什么时候去调。qrtz_cron_triggers(主要cron表达式信息),qrtz_triggers(存储了prev_fire_time,trigger_state,next_fire_time等触发要素).
- scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
- 清理某任务sql顺序:
----删除顺序应该这样,只有对cron_expression ,zone_id表达式记录。
DELETE FROM qrtz_cron_triggers WHERE trigger_name="snapshotAnalyzeSchedulerTriggerBean2";
DELETE FROM qrtz_triggers WHERE trigger_name="snapshotAnalyzeSchedulerTriggerBean2";
--只描述了具体job
DELETE FROM qrtz_job_details WHERE job_name="snapshotAnalyzeSchedulerJobDetail";
集群原理
一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。
图:表示了每个节点直接与数据库通信,若离开数据库将对其他节点一无所知
动态修改job
Quartz支持在scheduler.start();后动态addJob,ModifyJobTime,removeJob,pauseJob(停止任务),executeJob(立即执行任务)等。大家可以通过阅读代码来理解。
package com.calm.b.common.quartz;
import javax.annotation.Resource;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 定时任务调试引擎,负责完成定时任务的执行、启动、停止。。。
*/
@Service("scheduleJobEngine")
public class ScheduleJobEngine {
protected static Logger log = LoggerFactory.getLogger(ScheduleJobEngine.class);
private static SchedulerFactory schedulerFactory = null;
private static String JOB_GROUP_NAME = "DEFAULT";
private static String TRIGGER_GROUP_NAME = "TRIGGERGROUP_NAME";
/**
* 注入的spring Scheduler容器bean
*/
@Resource
private StdScheduler quartzScheduler;
/**
* 增加任务
*
* @param jobName
* @param jobClass
* @param expression
*/
public static void addJob(String jobName, String jobClass, String expression) {
addJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, jobClass, expression);
}
public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
String jobClass, String expression) {
log.debug("addJob:" + jobName);
try {
Scheduler scheduler = schedulerFactory.getScheduler();
// JobDetail jobDetail = new JobDetail(jobName, jobGroupName, Class.forName(jobClass));//
// 任务名,任务组,任务执行类
// // 触发器
// CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 触发器名,触发器组
// trigger.setCronExpression(expression);// 触发器时间设定
// scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 修改任务执行时间
*
* @param triggerName
* @param expression
*/
public static void modifyJobTime(String triggerName, String expression) {
modifyJobTime(triggerName, TRIGGER_GROUP_NAME, expression);
}
public static void modifyJobTime(String triggerName, String triggerGroupName, String expression) {
log.debug("modifyJobTime:" + triggerName);
try {
Scheduler scheduler = schedulerFactory.getScheduler();
CronTrigger trigger = null;
// = (CronTrigger) scheduler.getTrigger(triggerName, triggerGroupName);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(expression)) {
CronTrigger ct = (CronTrigger) trigger;
// 修改时间
// ct.setCronExpression(expression);
// 重启触发器
// scheduler.resumeTrigger(triggerName, triggerGroupName);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 移除任务
*
* @param jobName
*/
public static void removeJob(String jobName) {
removeJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME);
}
public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
log.debug("removeJob:" + jobName);
try {
// Scheduler scheduler = schedulerFactory.getScheduler();
// scheduler.pauseTrigger(triggerName, triggerGroupName);// 停止触发器
// scheduler.unscheduleJob(triggerName, triggerGroupName);// 移除触发器
// scheduler.deleteJob(jobName, jobGroupName);// 删除任务
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 停止任务
*
* @param jobName
*/
public void pauseJob(String jobName) {
pauseJob(jobName, JOB_GROUP_NAME);
}
public void pauseJob(String jobName, String jobGroupName) {
log.debug("pauseJob:" + jobName);
try {
quartzScheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 立即执行任务
*
* @param jobNam
* @param dataMap
*/
public void execJob(String jobName, JobDataMap dataMap) {
execJob(jobName, JOB_GROUP_NAME, dataMap);
}
public void execJob(String jobName) {
execJob(jobName, JOB_GROUP_NAME, new JobDataMap());
}
public void execJob(String jobName, String jobGroupName, JobDataMap dataMap) {
log.debug("execJob:" + jobName);
try {
quartzScheduler.triggerJob(JobKey.jobKey(jobName, jobGroupName), dataMap);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 恢复任务
*
* @param jobName
*/
public void resumeJob(String jobName) {
resumeJob(jobName, JOB_GROUP_NAME);
}
public void resumeJob(String jobName, String jobGroupName) {
log.debug("resumeJob:" + jobName);
try {
quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 启动所有定时任务
*/
public void startJobs() {
log.debug("startJobs");
try {
if (quartzScheduler.isShutdown()) {
quartzScheduler.start();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 关闭所有定时任务
*/
public void shutdownJobs() {
log.debug("shutdownJobs");
try {
if (!quartzScheduler.isShutdown()) {
quartzScheduler.shutdown();
}
// quartzScheduler.
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
参考文档
- 配置corn参考:http://www.cnblogs.com/skyblue/p/3296350.html
集群设置及原理参考:
http://sundoctor.iteye.com/blog/486055
http://blog.csdn.net/zxl315/article/details/10830105QuartzSchedulerThread核心代码:
http://blog.csdn.net/cutesource/article/details/4965520