領(lǐng)略Quartz源碼架構(gòu)之美——源碼實彈之Scheduler(二)

本章閱讀收獲:可了解Quartz框架中的Scheduler部分源碼

繼上一節(jié)內(nèi)容

上一節(jié)上我們講到了StdSchedulerFactory.getScheduler()中的initialize()方法风钻,下面我們繼續(xù)來講getScheduler()這塊內(nèi)容诈泼。

回顧getScheduler()代碼塊源碼

 /**
     * 獲取任務(wù)Schedule
     */
    @Override
    public Scheduler getScheduler() throws SchedulerException {
        //第一步加載配置文件类少,System的properties覆蓋前面的配置
        if (cfg == null) {
            initialize();
        }
        //本地存儲Schedule任務(wù),注:SchedulerRepository是單例模式
        SchedulerRepository schedRep = SchedulerRepository.getInstance();
        //從緩存中查詢獲取Schedule任務(wù),任務(wù)名稱從配置中獲取允跑,若無指定钞脂,則默認指定QuartzScheduler
        Scheduler sched = schedRep.lookup(getSchedulerName());
        //判斷若存在且已停止運行敛苇,則從緩存中移除
        if (sched != null) {
            if (sched.isShutdown()) {
                schedRep.remove(getSchedulerName());
            } else {
                return sched;
            }
        }
        //開始很多初始化對象
        sched = instantiate();

        return sched;
    }

在上一講中我們把instantiate()方法解析完成竭鞍,下面我們開始講SchedulerRepository。

SchedulerRepository源碼解析

package org.quartz.impl;

import java.util.Collection;
import java.util.HashMap;

import org.quartz.Scheduler;
import org.quartz.SchedulerException;

/**
 * <p>
 * 保持對調(diào)度器實例的引用-確保唯一性裆熙,以及
 * 防止垃圾收集桥滨,并允許“全球”查找-所有在一個
 * 類加載器空間。
 * </p>
 *
 * <person>
 *   調(diào)度程序庫弛车,采用單例模式存儲任務(wù)調(diào)度Schedule
 * </person>
 * @author James House
 */
public class SchedulerRepository {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Data members.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private HashMap<String, Scheduler> schedulers;

    private static SchedulerRepository inst;

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Constructors.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    private SchedulerRepository() {
        schedulers = new HashMap<String, Scheduler>();
    }

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Interface.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    public static synchronized SchedulerRepository getInstance() {
        if (inst == null) {
            inst = new SchedulerRepository();
        }

        return inst;
    }

    /**
     * 綁定新的任務(wù)調(diào)度器
     */
    public synchronized void bind(Scheduler sched) throws SchedulerException {

        if ((Scheduler) schedulers.get(sched.getSchedulerName()) != null) {
            throw new SchedulerException("Scheduler with name '"
                    + sched.getSchedulerName() + "' already exists.");
        }

        schedulers.put(sched.getSchedulerName(), sched);
    }

    /**
     * 移除新的任務(wù)調(diào)度器
     */
    public synchronized boolean remove(String schedName) {
        return (schedulers.remove(schedName) != null);
    }

    /**
     * 查詢新的任務(wù)調(diào)度器
     */
    public synchronized Scheduler lookup(String schedName) {
        return schedulers.get(schedName);
    }

    /**
     * 查詢所有任務(wù)調(diào)度器
     */
    public synchronized Collection<Scheduler> lookupAll() {
        return java.util.Collections
                .unmodifiableCollection(schedulers.values());
    }

}

可以看到這里其實就是使用內(nèi)存持久化任務(wù)調(diào)度器齐媒,非常簡單易懂,我們這不做展開纷跛。我們直接進入最重要喻括、最核心的instantiate()方法(不要和之前的initialize方法搞錯呦!F兜臁唬血!

instantiate源碼解析

由于這個過程非常的漫長,所以我們需要改一下之前的套路唤崭,需要逐個擊破拷恨,分而破之。下面是開頭的源碼:

 /**
     * 開始初始化各種所需對象實例
     * @return
     * @throws SchedulerException
     */
    private Scheduler instantiate() throws SchedulerException {
        if (cfg == null) {
            initialize();
        }

        if (initException != null) {
            throw initException;
        }
        //任務(wù)配置存儲
        JobStore js = null;
        //線程池
        ThreadPool tp = null;
        //實際調(diào)度器
        QuartzScheduler qs = null;
        //數(shù)據(jù)庫連接管理器
        DBConnectionManager dbMgr = null;
        //自動生成id類
        String instanceIdGeneratorClass = null;
        //配置文件
        Properties tProps = null;
        //用戶事務(wù)定位
        String userTXLocation = null;
        //包裝任務(wù)進事務(wù)中
        boolean wrapJobInTx = false;
        //是否自動
        boolean autoId = false;
        //服務(wù)器延遲
        long idleWaitTime = -1;
        // 15 secs 存儲失敗重試時間
        long dbFailureRetry = 15000L;
        //類加載幫助類
        String classLoadHelperClass;
        //任務(wù)工廠類
        String jobFactoryClass;
        //線程執(zhí)行器
        ThreadExecutor threadExecutor;

        //調(diào)用程序庫
        SchedulerRepository schedRep = SchedulerRepository.getInstance();

        // Get Scheduler Properties
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //PROP_SCHED_INSTANCE_NAME = org.quartz.scheduler.instanceName
        //設(shè)置調(diào)度器名字谢肾,默認是QuartzScheduler
        String schedName = cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,
                "QuartzScheduler");
        //PROP_SCHED_THREAD_NAME = org.quartz.scheduler.threadName
        //設(shè)置調(diào)度器線程名字腕侄,默認是調(diào)度器名字+_QuartzSchedulerThread
        String threadName = cfg.getStringProperty(PROP_SCHED_THREAD_NAME,
                schedName + "_QuartzSchedulerThread");
        //DEFAULT_INSTANCE_ID = NON_CLUSTERED
        //PROP_SCHED_INSTANCE_ID = org.quartz.scheduler.instanceId
        String schedInstId = cfg.getStringProperty(PROP_SCHED_INSTANCE_ID,
                DEFAULT_INSTANCE_ID);

        //AUTO_GENERATE_INSTANCE_ID = AUTO
        //這段if代碼邏輯是判斷是否用戶是否設(shè)置自動生成scheduleinstanceId自動生成
        //生成id的默認實現(xiàn)類是org.quartz.simpl.SimpleInstanceIdGenerator
        if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) {
            autoId = true;
            instanceIdGeneratorClass = cfg.getStringProperty(
                    PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS,
                    "org.quartz.simpl.SimpleInstanceIdGenerator");
        }
        // SYSTEM_PROPERTY_AS_INSTANCE_ID = SYS_PROP
        //生成id的默認實現(xiàn)類是org.quartz.simpl.SystemPropertyInstanceIdGenerator
        else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {
            autoId = true;
            instanceIdGeneratorClass = 
                    "org.quartz.simpl.SystemPropertyInstanceIdGenerator";
        }
        //PROP_SCHED_USER_TX_URL = org.quartz.scheduler.userTransactionURL
        userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL,
                userTXLocation);
        if (userTXLocation != null && userTXLocation.trim().length() == 0) {
            userTXLocation = null;
        }
        // PROP_SCHED_CLASS_LOAD_HELPER_CLASS = org.quartz.scheduler.classLoadHelper.class
        classLoadHelperClass = cfg.getStringProperty(
                PROP_SCHED_CLASS_LOAD_HELPER_CLASS,
                "org.quartz.simpl.CascadingClassLoadHelper");
        //PROP_SCHED_WRAP_JOB_IN_USER_TX = org.quartz.scheduler.wrapJobExecutionInUserTransaction
        wrapJobInTx = cfg.getBooleanProperty(PROP_SCHED_WRAP_JOB_IN_USER_TX,
                wrapJobInTx);
        //PROP_SCHED_JOB_FACTORY_CLASS = org.quartz.scheduler.jobFactory.class
        jobFactoryClass = cfg.getStringProperty(
                PROP_SCHED_JOB_FACTORY_CLASS, null);
        //PROP_SCHED_IDLE_WAIT_TIME = org.quartz.scheduler.idleWaitTime
        idleWaitTime = cfg.getLongProperty(PROP_SCHED_IDLE_WAIT_TIME,
                idleWaitTime);
        if(idleWaitTime > -1 && idleWaitTime < 1000) {
            throw new SchedulerException("org.quartz.scheduler.idleWaitTime of less than 1000ms is not legal.");
        }
        //PROP_SCHED_DB_FAILURE_RETRY_INTERVAL = org.quartz.scheduler.dbFailureRetryInterval
        dbFailureRetry = cfg.getLongProperty(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry);
        if (dbFailureRetry < 0) {
            throw new SchedulerException(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL + " of less than 0 ms is not legal.");
        }
        //PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON = org.quartz.scheduler.makeSchedulerThreadDaemon
        boolean makeSchedulerThreadDaemon =
            cfg.getBooleanProperty(PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON);
        //PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD =
        // org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer
        boolean threadsInheritInitalizersClassLoader =
            cfg.getBooleanProperty(PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD);
        //PROP_SCHED_BATCH_TIME_WINDOW = org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow
        long batchTimeWindow = cfg.getLongProperty(PROP_SCHED_BATCH_TIME_WINDOW, 0L);
        //PROP_SCHED_MAX_BATCH_SIZE = org.quartz.scheduler.batchTriggerAcquisitionMaxCount
        int maxBatchSize = cfg.getIntProperty(PROP_SCHED_MAX_BATCH_SIZE, 1);
        //PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN = org.quartz.scheduler.interruptJobsOnShutdown
        boolean interruptJobsOnShutdown = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN, false);
        //PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT = org.quartz.scheduler.interruptJobsOnShutdownWithWait
        boolean interruptJobsOnShutdownWithWait = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT, false);
        //PROP_SCHED_JMX_EXPORT = org.quartz.scheduler.jmx.export
        boolean jmxExport = cfg.getBooleanProperty(PROP_SCHED_JMX_EXPORT);
        //PROP_SCHED_JMX_OBJECT_NAME = org.quartz.scheduler.jmx.objectName
        String jmxObjectName = cfg.getStringProperty(PROP_SCHED_JMX_OBJECT_NAME);
        //PROP_SCHED_JMX_PROXY = org.quartz.scheduler.jmx.proxy
        boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY);
        //PROP_SCHED_JMX_PROXY_CLASS = org.quartz.scheduler.jmx.proxy.class
        String jmxProxyClass = cfg.getStringProperty(PROP_SCHED_JMX_PROXY_CLASS);
        //PROP_SCHED_RMI_EXPORT = org.quartz.scheduler.rmi.export
        boolean rmiExport = cfg.getBooleanProperty(PROP_SCHED_RMI_EXPORT, false);
        //PROP_SCHED_RMI_PROXY = org.quartz.scheduler.rmi.proxy
        boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY, false);
        //PROP_SCHED_RMI_HOST = org.quartz.scheduler.rmi.registryHost
        String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST, "localhost");
        //PROP_SCHED_RMI_PORT = org.quartz.scheduler.rmi.registryPort
        int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099);
        //PROP_SCHED_RMI_SERVER_PORT = org.quartz.scheduler.rmi.serverPort
        int rmiServerPort = cfg.getIntProperty(PROP_SCHED_RMI_SERVER_PORT, -1);
        //PROP_SCHED_RMI_CREATE_REGISTRY = org.quartz.scheduler.rmi.createRegistry
        String rmiCreateRegistry = cfg.getStringProperty(
                PROP_SCHED_RMI_CREATE_REGISTRY,
                //CREATE_REGISTRY_NEVER = never
                QuartzSchedulerResources.CREATE_REGISTRY_NEVER);
        //PROP_SCHED_RMI_BIND_NAME = org.quartz.scheduler.rmi.bindName
        String rmiBindName = cfg.getStringProperty(PROP_SCHED_RMI_BIND_NAME);

        if (jmxProxy && rmiProxy) {
            throw new SchedulerConfigException("Cannot proxy both RMI and JMX.");
        }
        //MANAGEMENT_REST_SERVICE_ENABLED = org.quartz.managementRESTService.enabled
        boolean managementRESTServiceEnabled = cfg.getBooleanProperty(MANAGEMENT_REST_SERVICE_ENABLED, false);
        //MANAGEMENT_REST_SERVICE_HOST_PORT = org.quartz.managementRESTService.bind
        String managementRESTServiceHostAndPort = cfg.getStringProperty(MANAGEMENT_REST_SERVICE_HOST_PORT, "0.0.0.0:9889");
        //PROP_SCHED_CONTEXT_PREFIX = org.quartz.context.key
        Properties schedCtxtProps = cfg.getPropertyGroup(PROP_SCHED_CONTEXT_PREFIX, true);
...
}

上面就是一些屬性的加載,其實功能非常簡單芦疏,就是從我們的配置文件中取出一些配置參數(shù)冕杠。具體的可以看下我的注釋。

結(jié)束語

本文講了instantiate()的屬性部分(好吧酸茴,其實就是水了一章)分预,有些人可能會說為什么我要介紹的那么詳細,主要還是可能本人有稍微一點強迫癥薪捍,之前看別人源碼都是一段一段的笼痹,就算讀懂了他貼的代碼的內(nèi)容配喳,但還是覺得心里不爽,說了那么多凳干,其實就是不想讓那些跟我一樣的人(好吧晴裹,其實就是我自己)心里不爽而已~~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纺座,隨后出現(xiàn)的幾起案子息拜,更是在濱河造成了極大的恐慌溉潭,老刑警劉巖净响,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喳瓣,居然都是意外死亡馋贤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門畏陕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來配乓,“玉大人,你說我怎么就攤上這事惠毁∮糖郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵鞠绰,是天一觀的道長腰埂。 經(jīng)常有香客問我,道長蜈膨,這世上最難降的妖魔是什么屿笼? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮翁巍,結(jié)果婚禮上驴一,老公的妹妹穿的比我還像新娘。我一直安慰自己灶壶,他們只是感情好肝断,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著驰凛,像睡著了一般孝情。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洒嗤,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天箫荡,我揣著相機與錄音,去河邊找鬼渔隶。 笑死羔挡,一個胖子當(dāng)著我的面吹牛洁奈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绞灼,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼利术,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了低矮?” 一聲冷哼從身側(cè)響起印叁,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎军掂,沒想到半個月后轮蜕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡蝗锥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年跃洛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片终议。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡汇竭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出穴张,到底是詐尸還是另有隱情细燎,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布皂甘,位于F島的核電站玻驻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叮贩。R本人自食惡果不足惜击狮,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望益老。 院中可真熱鬧彪蓬,春花似錦、人聲如沸捺萌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桃纯。三九已至酷誓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間态坦,已是汗流浹背盐数。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伞梯,地道東北人玫氢。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓帚屉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親漾峡。 傳聞我的和親對象是個殘疾皇子攻旦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評論 25 707
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料生逸? 從這篇文章中你...
    hw1212閱讀 12,732評論 2 59
  • 本章閱讀收獲:可了解Quartz框架中的Trigger部分源碼 無縫銜接 Job源碼看過之后牢屋,今天要分析的源碼在架...
    向光奔跑_閱讀 601評論 0 0
  • 你想要的愛情是什么樣的?是平平淡淡槽袄,還是轟轟烈烈烙无?有從一開始就特別膩歪的,也有一開始就平平淡淡的掰伸,你想要什...
    散wt閱讀 363評論 0 0
  • 剛畢業(yè)的時候我渴望有一份動人的工作皱炉,有了工作就有了寄托怀估,經(jīng)常沉浸在自己已經(jīng)長大了有工作的幸福里狮鸭。 來到深圳的我剛有...
    詩悠912閱讀 573評論 7 7