初次写作尝试:本文试以问答形式对quartz做一些介绍。
Ⅰ Quartz是什么?为什么要有这样一篇文章?
Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。Quartz最早的issue记录在jira.terracotta.org,时间可以追溯到大约2010年的2月。Quartz年代久远难以满足技术人的新奇感,也没有hadoop、spark那么重量、时髦,但深入了解一下这位老前辈的设计思想,仍能使我们获得一些开发方面的参考,这也正是本文的初衷。
Ⅱ 作业调度是什么?
想象一下,所有程序都是被动触发的,比如对于web程序,一次外部请求就是一次触发。有一类程序需要由时间触发,比如抢火车票的场景,每隔一段时间查询一次余票,最简单的实现,就是构造一个死循环,不断查询余票,每次启动主程序时,同时启动这个线程,这样就有了一个随时间周期性自动运行的程序。周期性触发称为一种调度规则,“由时间触发程序运行”就称为“作业调度”。
Ⅲ 我们为什么需要作业调度?
时间的流动不知疲倦永不停歇,由时间触发程序能自动化大量业务过程。
Ⅳ Quartz怎样实现作业调度?
仔细考虑一下我们需要的作业调度应该有些什么:
1.一个“调度者”,
2.一个“调度规则”,
3.一个被调度的“作业”
这三者可以构成一个有基本功能的作业调度,在quartz中,Scheduler对应“调度者”, Trigger对应“调度规则”,Job对应“作业”。
调度规则和作业配置在quartz的保存方式有很多实现,基于内存的RAMJobStore、基于JDBC的JobStoreSupport等等。在Scheduler和JobStore之间还有一层DriveDelegate,DriveDelegate非常像JobStore,只是扩展了基于不同database实现时的一些实现。Listener则提供了Scheduler、Trigger、Job运行时,一些时间点的通知。
自绘业务架构图:
Ⅴ 描述一下Quartz的一些基本活动?
首先是Quartz启动时的活动图:
看一下对应的源码片段:
启动的入口在QuartzScheduler的start:
1. 在QuartzScheduler.start()前,主调度线程SchedulerThread和其他配置通过StdSchedulerFactory初始化,源代码在StdSchedulerFactory.instantiate(),接近800行,此处不列举。
2. 检查Scheduler是否正在关闭或者已关闭。
3. 通知SchedulerListener正在启动。
4. 启动Scheduler,启动插件。
5. 如果Scheduler从暂停恢复运行,通知JobSupport恢复Scheduler。
6. 通知主调度线程开始运行。
7. 通知SchedulerListener启动完成。
public class QuartzScheduler implements RemotableQuartzScheduler {
public void start() throws SchedulerException {
// 检查Scheduler是否正在关闭或者已关闭 if (shuttingDown|| closed) {
throw new SchedulerException("The Scheduler cannot be restarted after shutdown() has been called."); }//通知SchedulerListener正在启动 notifySchedulerListenersStarting(); if (initialStart == null) {
initialStart = new Date();//启动Scheduler this.resources.getJobStore().schedulerStarted();//启动各种插件 startPlugins(); } else {
//如果Scheduler从暂停恢复运行,通知JobSupport恢复Scheduler resources.getJobStore().schedulerResumed(); }//通知主调度线程可以开始运行 schedThread.togglePause(false); //通知SchedulerListener启动完成 notifySchedulerListenersStarted(); }
}
通知监听:创建SchedulerListener的列表并逐个通知。
public class QuartzScheduler implements RemotableQuartzScheduler {
public void notifySchedulerListenersStarting() {
// 创建SchedulerListener的列表. List schedListeners = buildSchedulerListenerList(); // 逐个通知Listener for (SchedulerListener sl : schedListeners) {
sl.schedulerStarting(); }
}
}
获取监听列表:从ListenerManager获取Listener,这里需要开发者主动将自己的Listener注册到ListenerManager。
public class QuartzScheduler implements RemotableQuartzScheduler {
private ListbuildSchedulerListenerList() {
List allListeners = new LinkedList();// 从ListenerManager获取Listener 这里需要开发者主动将自己的Listener注册到ListenerManager allListeners.addAll(getListenerManager().getSchedulerListeners()); allListeners.addAll(getInternalSchedulerListeners()); return allListeners; }
}
正式启动Scheduler
1. 集群部署时初始化ClusterManager线程并启动。
2. 单机部署时恢复Job。
3. 初始化MisFire处理线程并启动。
public abstract class JobStoreSupportimplements JobStore,Constants {
public void schedulerStarted() throws SchedulerException {
// 集群部署时初始化ClusterManager线程并启动 if (isClustered()) {
clusterManagementThread = new ClusterManager(); clusterManagementThread.initialize(); } else {
//单机部署直接恢复Job recoverJobs(); }//初始化MisFire处理线程并启动 misfireHandler = new MisfireHandler(); misfireHandler.initialize(); }
}
首先初始化ClusterManager,把ClusterManager放进线程池执行。
class ClusterManager extends Thread {
public void initialize() {
// 初始化ClusterManager this.manage(); ThreadExecutor executor = getThreadExecutor();// 把ClusterManager放进线程池执行 executor.execute(ClusterManager.this); }
}
ClusterManage进一步doCheckin。
class ClusterManager extends Thread {
private boolean manage() {
boolean res = false; // 节点登入集群 res = doCheckin(); return res; }
}
Checkin细节:
1. 每次checkin都检查是否有意外中断的作业。
2. 从db获取锁后,再恢复作业。
public abstract class JobStoreSupportimplements JobStore,Constants {
protected boolean doCheckin() throws JobPersistenceException {
boolean recovered = false; Connection conn = getNonManagedTXConnection(); try {
// 每次都要检查是否有意外中断的作业 List failedRecords = null; if (!firstCheckIn) {
failedRecords = clusterCheckIn(conn); commitConnection(conn); }if (firstCheckIn || (failedRecords.size() > 0)) {
// 从db获取锁 getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS); transStateOwner = true; failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn); if (failedRecords.size() > 0) {
getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); // 恢复中断的作业 clusterRecover(conn, failedRecords); recovered = true; }
}
commitConnection(conn); } catch (JobPersistenceException e) {
rollbackConnection(conn); } finally {
}
firstCheckIn = false; return recovered; }
}
恢复作业:首先找到意外中断的调度记录,保存更新节点checkin的时间。
public abstract class JobStoreSupportimplements JobStore,Constants {
protected ListclusterCheckIn(Connection conn) throws JobPersistenceException {
//找到意外中断的调度记录 List failedInstances = findFailedInstances(conn); try {
// 保