美文网首页
领略Quartz源码架构之美——源码实弹之Scheduler(二

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

作者: 向光奔跑_ | 来源:发表于2018-11-19 19:04 被阅读0次

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

    相关文章

      网友评论

          本文标题:领略Quartz源码架构之美——源码实弹之Scheduler(二

          本文链接:https://www.haomeiwen.com/subject/rtwafqtx.html