Quartz 源码解析(二) —— Scheduler的初始化

一:初始化流程

// 创建一个ScheduleFactory
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
scheduler.start();

创建StdSchedulerFactory和StdScheduler。
SchedulerFacotory,顾名思义,就是生产Scheduler实例的工厂类。下面的代码逻辑这么多,就是为了创建一个Scheduler实例。

初始化流程

二:源码解析

创建SchedulerFacotory

SchedulerFacotory是一个接口,它有两个实现:

StdSchedulerFacotory通过配置文件来设置Scheduler的各项参数
DirectSchedulerFactory主要通过硬编码来设置Scheduler的各项参数。
  • 构造方法
    /**
     * Create an uninitialized StdSchedulerFactory.
     */
    public StdSchedulerFactory() {
    }

    /**
     * Create a StdSchedulerFactory that has been initialized via
     * <code>{@link #initialize(Properties)}</code>.
     *
     * @see #initialize(Properties)
     */
    public StdSchedulerFactory(Properties props) throws SchedulerException {
        initialize(props);
    }

    /**
     * Create a StdSchedulerFactory that has been initialized via
     * <code>{@link #initialize(String)}</code>.
     *
     * @see #initialize(String)
     */
    public StdSchedulerFactory(String fileName) throws SchedulerException {
        initialize(fileName);
    }
  • getScheduler()方法
    /**
     * <p>
     * Returns a handle to the Scheduler produced by this factory.
     * </p>
     *
     * <p>
     * If one of the <code>initialize</code> methods has not be previously
     * called, then the default (no-arg) <code>initialize()</code> method
     * will be called by this method.
     * </p>
     */
    public Scheduler getScheduler() throws SchedulerException {
        // 加载quartz.properties
        if (cfg == null) {
            initialize();
        }
        // 单例的SchedulerRepository实例
        SchedulerRepository schedRep = SchedulerRepository.getInstance();

        // 如果已经有类似的Scheduler启动了,就不用再创建了
        Scheduler sched = schedRep.lookup(getSchedulerName());

        if (sched != null) {
            if (sched.isShutdown()) {
                schedRep.remove(getSchedulerName());
            } else {
                return sched;
            }
        }

        // 初始化StdScheduler
        sched = instantiate();

        return sched;
    }

创建Scheduler

  • instantiate()
    创建资源的逻辑基本都在这个方法里面了,方法很长,有接近800行,"..."表示此处减去了一些我认为对理解创建流程不是很重要的代码。
/**
 * 创建ClassLoadHelper,以便根据配置文件提供的类名去创建实例
 * 获取quartz.properties的配置值
 * 创建ClassLoadHelper,以便根据配置文件提供的类名去创建实例
 * 创建JobFactory
 * 根据PropertiesParser创建ThreadPool
 * 根据PropertiesParser创建JobStore
 * 根据PropertiesParser创建DataSource
 * 根据PropertiesParser创建SchedulerPlugin
 * 根据PropertiesParser创建Listeners
 * 根据PropertiesParser创建ThreadExecutor
 * 根据PropertiesParser创建JobRunShellFactory
 * 创建QuartzSchedulerResources
 *   ThreadPool.initialize();
 *   new QuartzScheduler();
 *   StdScheduler的所有方法都委托给了QuartzScheduler;
 * @return
 * @throws SchedulerException
 */
private Scheduler instantiate() throws SchedulerException {
    ...
    JobStore js = null;
    ThreadPool tp = null;
    QuartzScheduler qs = null;
    DBConnectionManager dbMgr = null;
    String instanceIdGeneratorClass = null;
    Properties tProps = null;
    String userTXLocation = null;
    boolean wrapJobInTx = false;
    boolean autoId = false;
    long idleWaitTime = -1;
    long dbFailureRetry = 15000L; // 15 secs
    String classLoadHelperClass;
    String jobFactoryClass;
    ThreadExecutor threadExecutor;

    SchedulerRepository schedRep = SchedulerRepository.getInstance();

    // 获取quartz.properties的配置值
    String schedName = cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,
            "QuartzScheduler");
    ...

    // 创建ClassLoadHelper,以便根据配置文件提供的类名去创建实例
    ClassLoadHelper loadHelper = null;
    try {
        loadHelper = (ClassLoadHelper) loadClass(classLoadHelperClass)
                .newInstance();
    } catch (Exception e) {
        throw new SchedulerConfigException(
                "Unable to instantiate class load helper class: "
                        + e.getMessage(), e);
    }
    loadHelper.initialize();

    // If Proxying to remote JMX scheduler, short-circuit here...
    // TODO:代理是做什么的 和 RemoteMBeanScheduler的使用
    if (jmxProxy) {
        ...
    }

    // 创建JobFactory
    JobFactory jobFactory = null;
    if(jobFactoryClass != null) {
        try {
            jobFactory = (JobFactory) loadHelper.loadClass(jobFactoryClass)
                    .newInstance();
        } catch (Exception e) {
            throw new SchedulerConfigException(
                    "Unable to instantiate JobFactory class: "
                            + e.getMessage(), e);
        }

        tProps = cfg.getPropertyGroup(PROP_SCHED_JOB_FACTORY_PREFIX, true);
        try {
            setBeanProps(jobFactory, tProps);
        } catch (Exception e) {
            initException = new SchedulerException("JobFactory class '"
                    + jobFactoryClass + "' props could not be configured.", e);
            throw initException;
        }
    }
    ...

    // 根据PropertiesParser创建ThreadPool
    String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());

    if (tpClass == null) {
        initException = new SchedulerException("ThreadPool class not specified. ");
        throw initException;
    }

    try {
        tp = (ThreadPool) loadHelper.loadClass(tpClass).newInstance();
    } catch (Exception e) {
        initException = new SchedulerException("ThreadPool class '"
                + tpClass + "' could not be instantiated.", e);
        throw initException;
    }
    tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true);
    try {
        setBeanProps(tp, tProps);
    } catch (Exception e) {
        initException = new SchedulerException("ThreadPool class '"
                + tpClass + "' props could not be configured.", e);
        throw initException;
    }

    // 根据PropertiesParser创建JobStore
    String jsClass = cfg.getStringProperty(PROP_JOB_STORE_CLASS,
            RAMJobStore.class.getName());

    if (jsClass == null) {
        initException = new SchedulerException(
                "JobStore class not specified. ");
        throw initException;
    }

    try {
        js = (JobStore) loadHelper.loadClass(jsClass).newInstance();
    } catch (Exception e) {
        initException = new SchedulerException("JobStore class '" + jsClass
                + "' could not be instantiated.", e);
        throw initException;
    }

    SchedulerDetailsSetter.setDetails(js, schedName, schedInstId);

    tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true, new String[] {PROP_JOB_STORE_LOCK_HANDLER_PREFIX});
    try {
        setBeanProps(js, tProps);
    } catch (Exception e) {
        initException = new SchedulerException("JobStore class '" + jsClass
                + "' props could not be configured.", e);
        throw initException;
    }

    // 持久化的JobStore处理逻辑
    if (js instanceof JobStoreSupport) {
        // Install custom lock handler (Semaphore)
        String lockHandlerClass = cfg.getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS);
        if (lockHandlerClass != null) {
            try {
                Semaphore lockHandler = (Semaphore)loadHelper.loadClass(lockHandlerClass).newInstance();

                tProps = cfg.getPropertyGroup(PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true);

                // If this lock handler requires the table prefix, add it to its properties.
                if (lockHandler instanceof TablePrefixAware) {
                    tProps.setProperty(
                            PROP_TABLE_PREFIX, ((JobStoreSupport)js).getTablePrefix());
                    tProps.setProperty(
                            PROP_SCHED_NAME, schedName);
                }

                try {
                    setBeanProps(lockHandler, tProps);
                } catch (Exception e) {
                    initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass
                            + "' props could not be configured.", e);
                    throw initException;
                }

                ((JobStoreSupport)js).setLockHandler(lockHandler);
                getLog().info("Using custom data access locking (synchronization): " + lockHandlerClass);
            } catch (Exception e) {
                initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass
                        + "' could not be instantiated.", e);
                throw initException;
            }
        }
    }

    // Set up any DataSources
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 根据PropertiesParser创建DataSource
    String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);
    for (int i = 0; i < dsNames.length; i++) {
      ...
    }

    // 根据PropertiesParser创建SchedulerPlugin
    String[] pluginNames = cfg.getPropertyGroups(PROP_PLUGIN_PREFIX);
    SchedulerPlugin[] plugins = new SchedulerPlugin[pluginNames.length];
    for (int i = 0; i < pluginNames.length; i++) {
      ...
    }

    // 根据PropertiesParser创建Listeners
    Class<?>[] strArg = new Class[] { String.class };
    String[] jobListenerNames = cfg.getPropertyGroups(PROP_JOB_LISTENER_PREFIX);
    JobListener[] jobListeners = new JobListener[jobListenerNames.length];
    for (int i = 0; i < jobListenerNames.length; i++) {
      ...
    }

    String[] triggerListenerNames = cfg.getPropertyGroups(PROP_TRIGGER_LISTENER_PREFIX);
    TriggerListener[] triggerListeners = new TriggerListener[triggerListenerNames.length];
    for (int i = 0; i < triggerListenerNames.length; i++) {
      ...
    }

    boolean tpInited = false;
    boolean qsInited = false;

    // 根据PropertiesParser创建ThreadExecutor
    String threadExecutorClass = cfg.getStringProperty(PROP_THREAD_EXECUTOR_CLASS);
    if (threadExecutorClass != null) {
        tProps = cfg.getPropertyGroup(PROP_THREAD_EXECUTOR, true);
        try {
            threadExecutor = (ThreadExecutor) loadHelper.loadClass(threadExecutorClass).newInstance();
            log.info("Using custom implementation for ThreadExecutor: " + threadExecutorClass);

            setBeanProps(threadExecutor, tProps);
        } catch (Exception e) {
            initException = new SchedulerException(
                    "ThreadExecutor class '" + threadExecutorClass + "' could not be instantiated.", e);
            throw initException;
        }
    } else {
        log.info("Using default implementation for ThreadExecutor");
        threadExecutor = new DefaultThreadExecutor();
    }

    // Fire everything up
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    try {
        JobRunShellFactory jrsf = null; // Create correct run-shell factory...

        if (userTXLocation != null) {
            UserTransactionHelper.setUserTxLocation(userTXLocation);
        }

        if (wrapJobInTx) {
            jrsf = new JTAJobRunShellFactory();
        } else {
            jrsf = new JTAAnnotationAwareJobRunShellFactory();
        }

        if (autoId) {
            try {
              schedInstId = DEFAULT_INSTANCE_ID;
              if (js.isClustered()) {
                  schedInstId = instanceIdGenerator.generateInstanceId();
              }
            } catch (Exception e) {
                getLog().error("Couldn't generate instance Id!", e);
                throw new IllegalStateException("Cannot run without an instance id.");
            }
        }

        if (js.getClass().getName().startsWith("org.terracotta.quartz")) {
            try {
                String uuid = (String) js.getClass().getMethod("getUUID").invoke(js);
                if(schedInstId.equals(DEFAULT_INSTANCE_ID)) {
                    schedInstId = "TERRACOTTA_CLUSTERED,node=" + uuid;
                    if (jmxObjectName == null) {
                        jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);
                    }
                } else if(jmxObjectName == null) {
                    jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId + ",node=" + uuid);
                }
            } catch(Exception e) {
                throw new RuntimeException("Problem obtaining node id from TerracottaJobStore.", e);
            }

            if(null == cfg.getStringProperty(PROP_SCHED_JMX_EXPORT)) {
                jmxExport = true;
            }
        }

        if (js instanceof JobStoreSupport) {
            JobStoreSupport jjs = (JobStoreSupport)js;
            jjs.setDbRetryInterval(dbFailureRetry);
            if(threadsInheritInitalizersClassLoader)
                jjs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);

            jjs.setThreadExecutor(threadExecutor);
        }

        // 创建QuartzSchedulerResources
        QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();
        rsrcs.setName(schedName);
        rsrcs.setThreadName(threadName);
        rsrcs.setInstanceId(schedInstId);
        rsrcs.setJobRunShellFactory(jrsf);
        rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);
        rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);
        rsrcs.setBatchTimeWindow(batchTimeWindow);
        rsrcs.setMaxBatchSize(maxBatchSize);
        rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown);
        rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait);
        rsrcs.setJMXExport(jmxExport);
        rsrcs.setJMXObjectName(jmxObjectName);

        if (managementRESTServiceEnabled) {
            ManagementRESTServiceConfiguration managementRESTServiceConfiguration = new ManagementRESTServiceConfiguration();
            managementRESTServiceConfiguration.setBind(managementRESTServiceHostAndPort);
            managementRESTServiceConfiguration.setEnabled(managementRESTServiceEnabled);
            rsrcs.setManagementRESTServiceConfiguration(managementRESTServiceConfiguration);
        }

        if (rmiExport) {
            rsrcs.setRMIRegistryHost(rmiHost);
            rsrcs.setRMIRegistryPort(rmiPort);
            rsrcs.setRMIServerPort(rmiServerPort);
            rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry);
            rsrcs.setRMIBindName(rmiBindName);
        }

        SchedulerDetailsSetter.setDetails(tp, schedName, schedInstId);

        rsrcs.setThreadExecutor(threadExecutor);
        threadExecutor.initialize();

        rsrcs.setThreadPool(tp);
        if(tp instanceof SimpleThreadPool) {
            if(threadsInheritInitalizersClassLoader)
                ((SimpleThreadPool)tp).setThreadsInheritContextClassLoaderOfInitializingThread(threadsInheritInitalizersClassLoader);
        }
        tp.initialize();
        tpInited = true;

        rsrcs.setJobStore(js);

        // add plugins
        for (int i = 0; i < plugins.length; i++) {
            rsrcs.addSchedulerPlugin(plugins[i]);
        }

        qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry);
        qsInited = true;

        // Create Scheduler ref...
        Scheduler scheduler = instantiate(rsrcs, qs);

        // set job factory if specified
        if(jobFactory != null) {
            qs.setJobFactory(jobFactory);
        }

        // Initialize plugins now that we have a Scheduler instance.
        for (int i = 0; i < plugins.length; i++) {
            plugins[i].initialize(pluginNames[i], scheduler, loadHelper);
        }

        // add listeners
        for (int i = 0; i < jobListeners.length; i++) {
            qs.getListenerManager().addJobListener(jobListeners[i], EverythingMatcher.allJobs());
        }
        for (int i = 0; i < triggerListeners.length; i++) {
            qs.getListenerManager().addTriggerListener(triggerListeners[i], EverythingMatcher.allTriggers());
        }

        // set scheduler context data...
        for(Object key: schedCtxtProps.keySet()) {
            String val = schedCtxtProps.getProperty((String) key);    
            scheduler.getContext().put((String)key, val);
        }

        // fire up job store, and runshell factory

        js.setInstanceId(schedInstId);
        js.setInstanceName(schedName);
        js.setThreadPoolSize(tp.getPoolSize());
        js.initialize(loadHelper, qs.getSchedulerSignaler());

        jrsf.initialize(scheduler);

        qs.initialize();

        getLog().info(
                "Quartz scheduler '" + scheduler.getSchedulerName()
                        + "' initialized from " + propSrc);

        getLog().info("Quartz scheduler version: " + qs.getVersion());

        // prevents the repository from being garbage collected
        qs.addNoGCObject(schedRep);
        // prevents the db manager from being garbage collected
        if (dbMgr != null) {
            qs.addNoGCObject(dbMgr);
        }

        schedRep.bind(scheduler);
        return scheduler;
    }
    catch(SchedulerException e) {
        shutdownFromInstantiateException(tp, qs, tpInited, qsInited);
        throw e;
    }
    catch(RuntimeException re) {
        shutdownFromInstantiateException(tp, qs, tpInited, qsInited);
        throw re;
    }
    catch(Error re) {
        shutdownFromInstantiateException(tp, qs, tpInited, qsInited);
        throw re;
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值