quartz 启动后执行一次_老物重识Quartz

初次写作尝试:本文试以问答形式对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运行时,一些时间点的通知。

自绘业务架构图:

ef959363e77dab2433344aee21d45349.png

Ⅴ 描述一下Quartz的一些基本活动?

首先是Quartz启动时的活动图:

11a5d0cd2eed1f03e82c9aabee230b5d.png

看一下对应的源码片段:

启动的入口在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 {
    // 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值