精进Quartz的scheduler-start()启动源码分析

scheduler.start() 调用 .QuartzScheduler.start();

Quartz 的启动要调用start()方法进行线程的启动,并执行需要出发的Trigger,start方法里面进行的操作:

  • 1、启动的初始化
  • 2、判断是否集群,对应不同的操作
  • 3、若是非集群,首先有恢复机制,恢复任何失败或misfire的作业,并根据需要清理数据存储。
  • 4、初始化线程管理,唤醒所有等待的线程!

线程中启动线程是调用start()方法,但是真正执行线程任务的操作在run()中!

开启 scheduler调用start()

实际上调用QuartzScheduler对象的start();
下面就是简单的源码分析:

    /**
     * QuartzScheduler 的start方法
     * @throws SchedulerException
     */
    public void start() throws SchedulerException {

        if (shuttingDown|| closed) {
            throw new SchedulerException(
                    "The Scheduler cannot be restarted after shutdown() has been called.");
        }

        // QTZ-212 : calling new schedulerStarting() method on the listeners
        // right after entering start()
        notifySchedulerListenersStarting();

        //初始化标识为null,进行初始化操作
        if (initialStart == null) {
            initialStart = new Date();
            //1 主要分析的地方
            this.resources.getJobStore().schedulerStarted();
            startPlugins();
        } else {

            //2 如果已经初始化过,则恢复jobStore
            resources.getJobStore().schedulerResumed();
        }

        //3 唤醒所有等待的线程
        schedThread.togglePause(false);

        getLog().info(
                "Scheduler " + resources.getUniqueIdentifier() + " started.");

        notifySchedulerListenersStarted();
    

启动调度任务

this.resources.getJobStore().schedulerStarted() ;
主要分析的地方,实际上是调用 QuartzSchedulerResources中的JobStore进行启动,JobStore是接口,本例子的实现类是org.quartz.impl.jdbcjobstore.JobStoreSupport
看下面代码:

    /**
     * org.quartz.impl.jdbcjobstore.JobStoreSupport 调度开启
     * @throws SchedulerException
     */
    public void schedulerStarted() throws SchedulerException {
        //是集群
        if (isClustered()) {
            clusterManagementThread = new ClusterManager();
            if(initializersLoader != null)
                clusterManagementThread.setContextClassLoader(initializersLoader);
            clusterManagementThread.initialize();
        } else {//不是集群
            try {
                //1、恢复job
                recoverJobs();
            } catch (SchedulerException se) {
                throw new SchedulerConfigException(
                        "Failure occured during job recovery.", se);
            }
        }

        misfireHandler = new MisfireHandler();
        if(initializersLoader != null)
            misfireHandler.setContextClassLoader(initializersLoader);
        //2、 获取ThreadExecutor 线程管理
        misfireHandler.initialize();
        schedulerRunning = true;

        getLog().debug("JobStore background threads started (as scheduler was started).");
    }
1 、恢复job recoverJobs();
    /**
     * 启动的时候 有一个恢复机制
     * recoverJobs -----  将恢复任何失败或misfire的作业,并根据需要清理数据存储。
     * @throws JobPersistenceException
     */
    protected void recoverJobs() throws JobPersistenceException {
        executeInNonManagedTXLock(
                LOCK_TRIGGER_ACCESS,
                new VoidTransactionCallback() {
                    public void executeVoid(Connection conn) throws JobPersistenceException {
                        recoverJobs(conn);//恢复job
                    }
                }, null);
    }

我们继续往下看


   /**
     * 恢复任务状态
     * @param conn
     * @throws JobPersistenceException
     */
    protected void recoverJobs(Connection conn) throws JobPersistenceException {
        try {
        //1.更新不一致的作业状态  	先修改状态,将 ACQUIRED 和 BLOCKED ---> WAITING
            int rows = getDelegate().updateTriggerStatesFromOtherStates(conn,
                    STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED);

            rows += getDelegate().updateTriggerStatesFromOtherStates(conn,
                    STATE_PAUSED, STATE_PAUSED_BLOCKED, STATE_PAUSED_BLOCKED);

            //----更新sql---
            //"UPDATE {0}TRIGGERS SET TRIGGER_STATE = ? WHERE SCHED_NAME = {1} AND (TRIGGER_STATE = ? OR TRIGGER_STATE = ?)"

            getLog().info(
                    "Freed " + rows
                            + " triggers from 'acquired' / 'blocked' state.");

            // clean up misfired jobs
            //1.1 清理misfire的jobs
            recoverMisfiredJobs(conn, true);

            // recover jobs marked for recovery that were not fully executed
            //1.2 恢复未完全执行的标记为恢复的作业 --查询 qrtz_fire_trigger
            List<OperableTrigger> recoveringJobTriggers = getDelegate()
                    .selectTriggersForRecoveringJobs(conn);
            getLog().info("Recovering " + recoveringJobTriggers.size() + " jobs that were in-progress at the time of the last shut-down.");

            for (OperableTrigger recoveringJobTrigger: recoveringJobTriggers) {
                if (jobExists(conn, recoveringJobTrigger.getJobKey())) {
                    recoveringJobTrigger.computeFirstFireTime(null);
                    storeTrigger(conn, recoveringJobTrigger, null, false,
                            STATE_WAITING, false, true);
                }
            }
            getLog().info("Recovery complete.");

            // remove lingering 'complete' triggers...
            //1.3 移除state == complete
            List<TriggerKey> cts = getDelegate().selectTriggersInState(conn, STATE_COMPLETE);
            for(TriggerKey ct: cts) {
                removeTrigger(conn, ct);
            }
            getLog().info(
                    "Removed " + cts.size() + " 'complete' triggers.");

            // clean up any fired trigger entries
            //1.4 清理任何已触发的触发器条目
            int n = getDelegate().deleteFiredTriggers(conn);
            getLog().info("Removed " + n + " stale fired job entries.");
        } catch (JobPersistenceException e) {
            throw e;
        } catch (Exception e) {
            throw new JobPersistenceException("Couldn't recover jobs: " + e.getMessage(), e);
        }
    }

1.1 清理misfire的jobs recoverMisfiredJobs(conn, true);

    /**
     * 清理misfire的jobs
     * @param conn
     * @param recovering
     * @return
     * @throws JobPersistenceException
     * @throws SQLException
     */
    protected RecoverMisfiredJobsResult recoverMisfiredJobs(Connection conn, boolean recovering) throws JobPersistenceException, SQLException {
        int maxMisfiresToHandleAtATime = recovering ? -1 : this.getMaxMisfiresToHandleAtATime();
        List<TriggerKey> misfiredTriggers = new LinkedList();
        long earliestNewTime = Long.MAX_VALUE;
        /**
         * 是否有misfire的Trigger,我们必须仍然寻找MISFIRED状态,以防触发器被遗忘
         * getMisfireTime() 当前时间 -(减去) 一分钟 ,maxMisfiresToHandleAtATime == -1   ,misfiredTriggers== null
         *
         * "SELECT TRIGGER_NAME, TRIGGER_GROUP FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND NOT (MISFIRE_INSTR = -1) AND NEXT_FIRE_TIME < ? AND TRIGGER_STATE = ? ORDER BY NEXT_FIRE_TIME ASC, PRIORITY DESC"
         *
         *     上面sql查询出来结果是个list
         * 				(aa1)若resultList.size() == count 返回 TRUE!! 否则 返回false!
         * 				(aa2)不等于 count ,封装数据,到resultList中,triggername  TriggerGroup
         */
        boolean hasMoreMisfiredTriggers = this.getDelegate().hasMisfiredTriggersInState(conn, "WAITING", this.getMisfireTime(), maxMisfiresToHandleAtATime, misfiredTriggers);
        if (hasMoreMisfiredTriggers) {
            this.getLog().info("Handling the first " + misfiredTriggers.size() + " triggers that missed their scheduled fire-time.  " + "More misfired triggers remain to be processed.");
        } else {
            if (misfiredTriggers.size() <= 0) {
                this.getLog().debug("Found 0 triggers that missed their scheduled fire-time.");
                return RecoverMisfiredJobsResult.NO_OP;
            }

            this.getLog().info("Handling " + misfiredTriggers.size() + " trigger(s) that missed their scheduled fire-time.");
        }

        Iterator i$ = misfiredTriggers.iterator();

        //循环 misfiredTriggers List集合
        while(i$.hasNext()) {
            TriggerKey triggerKey = (TriggerKey)i$.next();
            //retrieveTrigger ,检索Trigger,检索到进行数据封装
            /**
             *	 //retrieveTrigger 执行的操作
             * 					(1)"SELECT * FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?"
             * 					(2)关联Trigger对应的类型,如simpleTrigger等
             */
            OperableTrigger trig = this.retrieveTrigger(conn, triggerKey);
            if (trig != null) {
                //do 更新misfire的触发器
                this.doUpdateOfMisfiredTrigger(conn, trig, false, "WAITING", recovering);
                if (trig.getNextFireTime() != null && trig.getNextFireTime().getTime() < earliestNewTime) {
                    earliestNewTime = trig.getNextFireTime().getTime();
                }
            }
        }

        return new RecoverMisfiredJobsResult(hasMoreMisfiredTriggers, misfiredTriggers.size(), earliestNewTime);
    }

1.2 更新misfire的触发器 doUpdateOfMisfiredTrigger(conn, trig, false, “WAITING”, recovering);

    /**
     * 更新misfire的触发器
     * @param conn
     * @param trig
     * @param forceState
     * @param newStateIfNotComplete
     * @param recovering
     * @throws JobPersistenceException
     */
    private void doUpdateOfMisfiredTrigger(Connection conn, OperableTrigger trig, boolean forceState, String newStateIfNotComplete, boolean recovering) throws JobPersistenceException {
        Calendar cal = null;
        if (trig.getCalendarName() != null) {
            /**
             * 操作这个表qrtz_calendar
             */
            cal = this.retrieveCalendar(conn, trig.getCalendarName());
        }

        this.schedSignaler.notifyTriggerListenersMisfired(trig);
        //simpleTrigger默认的misfire 机制,设置下次执行的时间(next_fire_time)为当前时间!这里比较重要!!!
        trig.updateAfterMisfire(cal);
        if (trig.getNextFireTime() == null) {
            this.storeTrigger(conn, trig, (JobDetail)null, true, "COMPLETE", forceState, recovering);
            this.schedSignaler.notifySchedulerListenersFinalized(trig);
        } else {
            this.storeTrigger(conn, trig, (JobDetail)null, true, newStateIfNotComplete, forceState, recovering);
        }

    }

1.3、 恢复未完全执行的标记为恢复的作业selectTriggersForRecoveringJobs,代码片段如下


List<OperableTrigger> recoveringJobTriggers = getDelegate()
    .selectTriggersForRecoveringJobs(conn);					
// INSTANCE_NAME == dufy_test    REQUESTS_RECOVERY == true  实际封装到数据库查询是 REQUESTS_RECOVERY== 1
"SELECT * FROM {0}FIRED_TRIGGERS WHERE SCHED_NAME = {1} AND INSTANCE_NAME = ? AND REQUESTS_RECOVERY = ?"
    //具体怎么是 true是怎么转换成为 1的见附1图片!

  Recovery complete.恢复完成!!	

1.4 移除state == complete

List<TriggerKey> cts = getDelegate().selectTriggersInState(conn, STATE_COMPLETE);
-----------------------------------------------------------------------------
    "SELECT TRIGGER_NAME, TRIGGER_GROUP FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_STATE = ?"
    -----------------------------------------------------------------------------
    for(TriggerKey ct: cts) {
        removeTrigger(conn, ct);
        ---------------------------------------------------------------------
            (a)删除前,先查询jobDetail
            JobDetail job = getDelegate().selectJobForTrigger(conn,getClassLoadHelper(), key, false);
        "SELECT J.JOB_NAME, J.JOB_GROUP, J.IS_DURABLE, J.JOB_CLASS_NAME, J.REQUESTS_RECOVERY FROM {0}TRIGGERS T, {0}JOB_DETAILS J WHERE T.SCHED_NAME = {1} AND J.SCHED_NAME = {1} AND T.TRIGGER_NAME = ? AND T.TRIGGER_GROUP = ? AND T.JOB_NAME = J.JOB_NAME AND T.JOB_GROUP = J.JOB_GROUP"

            (b)删除触发器,其侦听器及其Simple / Cron / BLOB子表条目。
            boolean removedTrigger = deleteTriggerAndChildren(conn, key);
        deleteTrigger(Connection conn, TriggerKey triggerKey)
            (b1)deleteTriggerExtension
            "DELETE FROM {0}SIMPLE_TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?"
            "DELETE FROM {0}BLOB_TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?"

            (b2)"DELETE FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?"

            (c)是否删除jobdetail ,判断 isDurable 默认 为falseif (null != job && !job.isDurable()) {
                int numTriggers = getDelegate().selectNumTriggersForJob(conn,
                                                                        job.getKey());
                ---------------------------------------------------------
                    "SELECT COUNT(TRIGGER_NAME) FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?"
                    ---------------------------------------------------------
                    if (numTriggers == 0) {
                        // Don't call removeJob() because we don't want to check for
                        // triggers again.
                        //不要调用removeJob(),因为我们不想再次检查触发器。
                        deleteJobAndChildren(conn, job.getKey()); //删除作业及其侦听器。
                        -----------------------------------------------------
                            //deleteJobDetail(Connection conn, JobKey jobKey) 删除给定作业的作业明细记录。
                            "DELETE FROM {0}JOB_DETAILS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?"
                            -----------------------------------------------------
                    }
            }
    }

1.5 清理任何已触发的触发器条目

 int n = getDelegate().deleteFiredTriggers(conn);
 ----------------------------------------------------------------------------
 "DELETE FROM {0}FIRED_TRIGGERS WHERE SCHED_NAME = {1}"
 ----------------------------------------------------------------------------
2、获取ThreadExecutor 线程管理 misfireHandler.initialize();
public void initialize() {
		ThreadExecutor executor = getThreadExecutor();
		//getThreadExecutor ==  private ThreadExecutor threadExecutor = new DefaultThreadExecutor();
		executor.execute(MisfireHandler.this); //启动线程执行 对应job的 execute方法
		//MisfireHandler  ==  class MisfireHandler extends Thread  继承了Thread
}

如果已经初始化过,则恢复

jobStoreresources.getJobStore().schedulerResumed();.如果已经初始化过,则恢复调度器运行 !

private volatile boolean schedulerRunning = false;//默认schedulerRunning = false
public void schedulerResumed() {
    schedulerRunning = true;
}

唤醒所有等待的线程

schedThread.togglePause(false);

schedThread.togglePause(false);
//指示主处理循环在下一个可能的点暂停。
void togglePause(boolean pause) {
    synchronized (sigLock) {
        paused = pause;

        if (paused) {
            signalSchedulingChange(0);
            ------------------------------------------
                //发信号通知主要处理循环,已经进行了调度的改变 - 以便中断在等待misfire时间到达时可能发生的任何睡眠。
                public void signalSchedulingChange(long candidateNewNextFireTime) {
                synchronized(sigLock) {
                    signaled = true;
                    signaledNextFireTime = candidateNewNextFireTime;
                    sigLock.notifyAll();  // private final Object sigLock = new Object();
                }
            }
            ------------------------------------------
        } else {
            sigLock.notifyAll();//唤醒所有等待的线程
        }
    }
}	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值