领略Quartz源码架构之美——源码实弹之Scheduler(二)

本章阅读收获:可了解Quartz框架中的Scheduler部分源码

继上一节内容

上一节上我们讲到了StdSchedulerFactory.getScheduler()中的initialize()方法,下面我们继续来讲getScheduler()这块内容。

回顾getScheduler()代码块源码

 /**
     * 获取任务Schedule
     */
    @Override
    public Scheduler getScheduler() throws SchedulerException {
        //第一步加载配置文件,System的properties覆盖前面的配置
        if (cfg == null) {
            initialize();
        }
        //本地存储Schedule任务,注:SchedulerRepository是单例模式
        SchedulerRepository schedRep = SchedulerRepository.getInstance();
        //从缓存中查询获取Schedule任务,任务名称从配置中获取,若无指定,则默认指定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>
 * 保持对调度器实例的引用-确保唯一性,以及
 * 防止垃圾收集,并允许“全球”查找-所有在一个
 * 类加载器空间。
 * </p>
 *
 * <person>
 *   调度程序库,采用单例模式存储任务调度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;
    }

    /**
     * 绑定新的任务调度器
     */
    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);
    }

    /**
     * 移除新的任务调度器
     */
    public synchronized boolean remove(String schedName) {
        return (schedulers.remove(schedName) != null);
    }

    /**
     * 查询新的任务调度器
     */
    public synchronized Scheduler lookup(String schedName) {
        return schedulers.get(schedName);
    }

    /**
     * 查询所有任务调度器
     */
    public synchronized Collection<Scheduler> lookupAll() {
        return java.util.Collections
                .unmodifiableCollection(schedulers.values());
    }

}

可以看到这里其实就是使用内存持久化任务调度器,非常简单易懂,我们这不做展开。我们直接进入最重要、最核心的instantiate()方法(不要和之前的initialize方法搞错呦!!!

instantiate源码解析

由于这个过程非常的漫长,所以我们需要改一下之前的套路,需要逐个击破,分而破之。下面是开头的源码:

 /**
     * 开始初始化各种所需对象实例
     * @return
     * @throws SchedulerException
     */
    private Scheduler instantiate() throws SchedulerException {
        if (cfg == null) {
            initialize();
        }

        if (initException != null) {
            throw initException;
        }
        //任务配置存储
        JobStore js = null;
        //线程池
        ThreadPool tp = null;
        //实际调度器
        QuartzScheduler qs = null;
        //数据库连接管理器
        DBConnectionManager dbMgr = null;
        //自动生成id类
        String instanceIdGeneratorClass = null;
        //配置文件
        Properties tProps = null;
        //用户事务定位
        String userTXLocation = null;
        //包装任务进事务中
        boolean wrapJobInTx = false;
        //是否自动
        boolean autoId = false;
        //服务器延迟
        long idleWaitTime = -1;
        // 15 secs 存储失败重试时间
        long dbFailureRetry = 15000L;
        //类加载帮助类
        String classLoadHelperClass;
        //任务工厂类
        String jobFactoryClass;
        //线程执行器
        ThreadExecutor threadExecutor;

        //调用程序库
        SchedulerRepository schedRep = SchedulerRepository.getInstance();

        // Get Scheduler Properties
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //PROP_SCHED_INSTANCE_NAME = org.quartz.scheduler.instanceName
        //设置调度器名字,默认是QuartzScheduler
        String schedName = cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,
                "QuartzScheduler");
        //PROP_SCHED_THREAD_NAME = org.quartz.scheduler.threadName
        //设置调度器线程名字,默认是调度器名字+_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代码逻辑是判断是否用户是否设置自动生成scheduleinstanceId自动生成
        //生成id的默认实现类是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的默认实现类是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);
...
}

上面就是一些属性的加载,其实功能非常简单,就是从我们的配置文件中取出一些配置参数。具体的可以看下我的注释。

结束语

本文讲了instantiate()的属性部分(好吧,其实就是水了一章),有些人可能会说为什么我要介绍的那么详细,主要还是可能本人有稍微一点强迫症,之前看别人源码都是一段一段的,就算读懂了他贴的代码的内容,但还是觉得心里不爽,说了那么多,其实就是不想让那些跟我一样的人(好吧,其实就是我自己)心里不爽而已~~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,171评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,732评论 2 59
  • 本章阅读收获:可了解Quartz框架中的Trigger部分源码 无缝衔接 Job源码看过之后,今天要分析的源码在架...
    向光奔跑_阅读 601评论 0 0
  • 你想要的爱情是什么样的?是平平淡淡,还是轰轰烈烈?有从一开始就特别腻歪的,也有一开始就平平淡淡的,你想要什...
    散wt阅读 363评论 0 0
  • 刚毕业的时候我渴望有一份动人的工作,有了工作就有了寄托,经常沉浸在自己已经长大了有工作的幸福里。 来到深圳的我刚有...
    诗悠912阅读 573评论 7 7