quartz的schedulerFactory实现解析

由于需要实现一个scheduler,用于添加job,更改job等功能,但是没有调度功能。没错主要是用于监控和管理集群用的。所以需要仔细看scheduler的接口规范,于是又了这篇文章。

SchedulerFactory 是一个接口,用于Scheduler的创建和管理。接口很简单,这里主要是解析StdSchedulerFactory 的实现方式。

1、构造函数:

[java]  view plain  copy
  1. public StdSchedulerFactory(Properties props) throws SchedulerException {  
[java]  view plain  copy
  1.     //把初始化参数代理给<span style="font-family: Arial, Helvetica, sans-serif;">initialize,通过Properties来做初始化</span>  
  2.     initialize(props);  
  3. }  
  4. public StdSchedulerFactory(String fileName) throws SchedulerException {  
[java]  view plain  copy
  1.     //通过配置文件初始化,这也会把文件解析为Properties  
  2.     initialize(fileName);  
  3. }  

2、初始化过程

    初始化过程,首先会看是否传入了配置文件或Properties属性,没有的话,会根据系统变量--》工程classpath--》quartz的包的顺序查找quartz.properties文件

    查找配置文件过程如下:

[java]  view plain  copy
  1. public void initialize() throws SchedulerException {  
  2.         // short-circuit if already initialized  
  3.         if (cfg != null) {//找到文件后会构建一个cfg属性,所以如果cfg!=null说明已经初始化过了  
  4.             return;  
  5.         }  
  6.         if (initException != null) {  
  7.             throw initException;  
  8.         }  
  9.         //通过查找系统变量查找配置文件  
  10.         String requestedFile = System.getProperty(PROPERTIES_FILE);  
[java]  view plain  copy
  1. //如果没有找到就用默认的文件名  
  2.  String propFileName = requestedFile != null ? requestedFile  
  3.          : "quartz.properties";  
[java]  view plain  copy
  1. File propFile = new File(propFileName);  
  2.   
  3. Properties props = new Properties();  
  4.   
  5. InputStream in = null;  
  6.   
  7. try {  
[java]  view plain  copy
  1. //先查看指定的配置文件是否存在,存在就读取,注意这里的读取方式用文件系统的路径来读取的  
  2.  if (propFile.exists()) {  
  3.      try {  
  4.          if (requestedFile != null) {  
  5.              propSrc = "specified file: '" + requestedFile + "'";  
  6.          } else {  
  7.              propSrc = "default file in current working dir: 'quartz.properties'";  
  8.          }  
  9.            
  10.          in = new BufferedInputStream(new FileInputStream(propFileName));  
  11.          props.load(in);  
  12.   
  13.      } catch (IOException ioe) {  
  14.          initException = new SchedulerException("Properties file: '"  
  15.                  + propFileName + "' could not be read.", ioe);  
  16.          throw initException;  
  17.      }  
[java]  view plain  copy
  1. //如果通过文件系统的路径读不到,那么就通过<span style="font-family: Arial, Helvetica, sans-serif;">ContextClassLoader的</span>路径来读取  
  2.  } else if (requestedFile != null) {  
  3.      in =  
  4.          Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile);  
  5.   
  6.      if(in == null) {  
  7.          initException = new SchedulerException("Properties file: '"  
  8.              + requestedFile + "' could not be found.");  
  9.          throw initException;  
  10.      }  
  11.   
  12.      propSrc = "specified file: '" + requestedFile + "' in the class resource path.";  
  13.   
  14.      in = new BufferedInputStream(in);  
  15.      try {  
  16.          props.load(in);  
  17.      } catch (IOException ioe) {  
  18.          initException = new SchedulerException("Properties file: '"  
  19.                  + requestedFile + "' could not be read.", ioe);  
  20.          throw initException;  
  21.      }  
  22.   
  23.  } else {  
  24.      propSrc = "default resource file in Quartz package: 'quartz.properties'";  
  25.      //通过当前的classLoader来读取,但是一般情况下这个和当前线程的classLoader基本是一个  
  26.      ClassLoader cl = getClass().getClassLoader();  
  27.      if(cl == null)  
  28.          cl = findClassloader();  
  29.      if(cl == null)  
  30.          throw new SchedulerConfigException("Unable to find a class loader on the current thread or class.");  
  31.   
  32.      in = cl.getResourceAsStream(  
  33.              "quartz.properties");  
  34.   
  35.      if (in == null) {  
  36.          in = cl.getResourceAsStream(  
  37.                  "/quartz.properties");  
  38.      }  
[java]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;">                //是在找不到,那么就从quartz的包找了</span>  
[java]  view plain  copy
  1.         if (in == null) {  
  2.             in = cl.getResourceAsStream(  
  3.                     "org/quartz/quartz.properties");  
  4.         }  
  5.         if (in == null) {  
  6.             initException = new SchedulerException(  
  7.                     "Default quartz.properties not found in class path");  
  8.             throw initException;  
  9.         }  
  10.         try {  
  11.             props.load(in);  
  12.         } catch (IOException ioe) {  
  13.             initException = new SchedulerException(  
  14.                     "Resource properties file: 'org/quartz/quartz.properties' "  
  15.                             + "could not be read from the classpath.", ioe);  
  16.             throw initException;  
  17.         }  
  18.     }  
  19. finally {  
  20.     if(in != null) {  
  21.         try { in.close(); } catch(IOException ignore) { /* ignore */ }  
  22.     }  
  23. }  
  24. //最后解析为一个Properties去配置schuduler  
  25. initialize(overrideWithSysProps(props));  


上面都在准备配置信息,这些最后会生成一个Cfg对象,用它去获取属性,配置Scheduler,在调用

[java]  view plain  copy
  1. Scheduler getScheduler()  
的时候根据会首先检查是否已经创建了,没有创建会根据这些属性创建新的Scheduler:

[java]  view plain  copy
  1. instantiate()  
instantiate的关键代码:
关键属性:

[java]  view plain  copy
  1. JobStore js = null;  
  2.         ThreadPool tp = null;  
  3.         QuartzScheduler qs = null;  
  4.         DBConnectionManager dbMgr = null;  
  5.         String instanceIdGeneratorClass = null;  
  6.         Properties tProps = null;  
  7.         String userTXLocation = null;  
  8.         boolean wrapJobInTx = false;  
  9.         boolean autoId = false;  
  10.         long idleWaitTime = -1;  
  11.         long dbFailureRetry = 15000L; // 15 secs  
  12.         String classLoadHelperClass;  
  13.         String jobFactoryClass;  
  14.         ThreadExecutor threadExecutor;  
schedulerId的生成:

[java]  view plain  copy
  1. String schedInstId = cfg.getStringProperty(PROP_SCHED_INSTANCE_ID,  
  2.                DEFAULT_INSTANCE_ID);  
  3.   
  4.        //如果配置成自动生成,那么就去获取自动生成器生成  
  5.        if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) {  
  6.            autoId = true;  
  7.            instanceIdGeneratorClass = cfg.getStringProperty(  
  8.                    PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS,  
  9.                    "org.quartz.simpl.SimpleInstanceIdGenerator");  
  10.        }  
[java]  view plain  copy
  1. //如果配置成系统属性Id,那么就用相应的class生成  
  2. else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {  
  3.     autoId = true;  
  4.     instanceIdGeneratorClass =   
  5.             "org.quartz.simpl.SystemPropertyInstanceIdGenerator";  
  6. }  
获取UserTansaction的Jndi url,在分布式事务中使用

[java]  view plain  copy
  1. userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL,  
  2.                userTXLocation);  
是否用UserTansaction来执行Job:

[java]  view plain  copy
  1. wrapJobInTx = cfg.getBooleanProperty(PROP_SCHED_WRAP_JOB_IN_USER_TX,  
  2.                 wrapJobInTx);  

job实例化factory:

[java]  view plain  copy
  1. jobFactoryClass = cfg.getStringProperty(  
  2.                PROP_SCHED_JOB_FACTORY_CLASS, null);  

jmx设置相关:

[java]  view plain  copy
  1. boolean jmxExport = cfg.getBooleanProperty(PROP_SCHED_JMX_EXPORT);  
  2. String jmxObjectName = cfg.getStringProperty(PROP_SCHED_JMX_OBJECT_NAME);  
  3.          
  4. boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY);  
  5. String jmxProxyClass = cfg.getStringProperty(PROP_SCHED_JMX_PROXY_CLASS);  

rmi相关:

[java]  view plain  copy
  1. boolean rmiExport = cfg.getBooleanProperty(PROP_SCHED_RMI_EXPORT, false);  
  2. boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY, false);  
  3. String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST, "localhost");  
  4. int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099);  
  5. int rmiServerPort = cfg.getIntProperty(PROP_SCHED_RMI_SERVER_PORT, -1);  
  6. String rmiCreateRegistry = cfg.getStringProperty(  
  7.         PROP_SCHED_RMI_CREATE_REGISTRY,  
  8.         QuartzSchedulerResources.CREATE_REGISTRY_NEVER);  
  9. String rmiBindName = cfg.getStringProperty(PROP_SCHED_RMI_BIND_NAME);  

不过Jmx和rmi是不能同时开启的:

[java]  view plain  copy
  1. if (jmxProxy && rmiProxy) {  
  2.           throw new SchedulerConfigException("Cannot proxy both RMI and JMX.");  
  3.       }  


如果是rmi代理的就创建remoteScheduler:(不会有集群效果,毕竟所有操作都是远程那边在做)

[java]  view plain  copy
  1. if (rmiProxy) {  
  2.   
  3.             if (autoId) {  
  4.                 schedInstId = DEFAULT_INSTANCE_ID;  
  5.             }  
  6.   
  7.             String uid = (rmiBindName == null) ? QuartzSchedulerResources.getUniqueIdentifier(  
  8.                     schedName, schedInstId) : rmiBindName;  
  9.   
  10.             RemoteScheduler remoteScheduler = new RemoteScheduler(uid, rmiHost, rmiPort);  
  11.   
  12.             schedRep.bind(remoteScheduler);  
  13.   
  14.             return remoteScheduler;  
  15.         }  

如果是jmx远程代理就用jmxscheduler:

[java]  view plain  copy
  1. if (jmxProxy) {  
  2.           if (autoId) {  
  3.               schedInstId = DEFAULT_INSTANCE_ID;  
  4.           }  
  5.   
  6.           if (jmxProxyClass == null) {  
  7.               throw new SchedulerConfigException("No JMX Proxy Scheduler class provided");  
  8.           }  
  9.   
  10.           RemoteMBeanScheduler jmxScheduler = null;  
  11.           try {  
  12.               jmxScheduler = (RemoteMBeanScheduler)loadHelper.loadClass(jmxProxyClass)  
  13.                       .newInstance();  
  14.           } catch (Exception e) {  
  15.               throw new SchedulerConfigException(  
  16.                       "Unable to instantiate RemoteMBeanScheduler class.", e);  
  17.           }  
  18.   
  19.           if (jmxObjectName == null) {  
  20.               jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);  
  21.           }  
  22.   
  23.           jmxScheduler.setSchedulerObjectName(jmxObjectName);  
  24.   
  25.           tProps = cfg.getPropertyGroup(PROP_SCHED_JMX_PROXY, true);  
  26.           try {  
  27.               setBeanProps(jmxScheduler, tProps);  
  28.           } catch (Exception e) {  
  29.               initException = new SchedulerException("RemoteMBeanScheduler class '"  
  30.                       + jmxProxyClass + "' props could not be configured.", e);  
  31.               throw initException;  
  32.           }  
  33.   
  34.           jmxScheduler.initialize();  
  35.   
  36.           schedRep.bind(jmxScheduler);  
  37.   
  38.           return jmxScheduler;  
  39.       }  

初始化jobFactory:

[java]  view plain  copy
  1. JobFactory jobFactory = null;  
  2.         if(jobFactoryClass != null) {  
  3.             try {  
  4.                 jobFactory = (JobFactory) loadHelper.loadClass(jobFactoryClass)  
  5.                         .newInstance();  
  6.             } catch (Exception e) {  
  7.                 throw new SchedulerConfigException(  
  8.                         "Unable to instantiate JobFactory class: "  
  9.                                 + e.getMessage(), e);  
  10.             }  
  11.             //获取jobFactory需要的属性,这里的方法就是定义自定义属性名(固定前缀)的实现方式,比如说常用的datasource  
  12.             tProps = cfg.getPropertyGroup(PROP_SCHED_JOB_FACTORY_PREFIX, true);  
  13.             try {  
  14.                 setBeanProps(jobFactory, tProps);  
  15.             } catch (Exception e) {  
  16.                 initException = new SchedulerException("JobFactory class '"  
  17.                         + jobFactoryClass + "' props could not be configured.", e);  
  18.                 throw initException;  
  19.             }  
  20.         }  
配置ThreadPool,属性值的获取方式和JobFactory一直:

[java]  view plain  copy
  1. String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());  
  2.   
  3.       if (tpClass == null) {  
  4.           initException = new SchedulerException(  
  5.                   "ThreadPool class not specified. ");  
  6.           throw initException;  
  7.       }  
  8.   
  9.       try {  
  10.           tp = (ThreadPool) loadHelper.loadClass(tpClass).newInstance();  
  11.       } catch (Exception e) {  
  12.           initException = new SchedulerException("ThreadPool class '"  
  13.                   + tpClass + "' could not be instantiated.", e);  
  14.           throw initException;  
  15.       }  
  16.       tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true);  
  17.       try {  
  18.           setBeanProps(tp, tProps);  
  19.       } catch (Exception e) {  
  20.           initException = new SchedulerException("ThreadPool class '"  
  21.                   + tpClass + "' props could not be configured.", e);  
  22.           throw initException;  
  23.       }  
jobStore的配置:

[java]  view plain  copy
  1. String jsClass = cfg.getStringProperty(PROP_JOB_STORE_CLASS,  
  2.               RAMJobStore.class.getName());  
  3.   
  4.       if (jsClass == null) {  
  5.           initException = new SchedulerException(  
  6.                   "JobStore class not specified. ");  
  7.           throw initException;  
  8.       }  
  9.   
  10.       try {  
  11.           js = (JobStore) loadHelper.loadClass(jsClass).newInstance();  
  12.       } catch (Exception e) {  
  13.           initException = new SchedulerException("JobStore class '" + jsClass  
  14.                   + "' could not be instantiated.", e);  
  15.           throw initException;  
  16.       }  
  17.       //设置JobStore的scheduleName和scheduleId两个值,就是简单的反射设置而已  
  18.       SchedulerDetailsSetter.setDetails(js, schedName, schedInstId);  
  19.   
  20.       tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, truenew String[] {PROP_JOB_STORE_LOCK_HANDLER_PREFIX});  
  21.       try {  
  22.           setBeanProps(js, tProps);  
  23.       } catch (Exception e) {  
  24.           initException = new SchedulerException("JobStore class '" + jsClass  
  25.                   + "' props could not be configured.", e);  
  26.           throw initException;  
  27.       }  
  28.       //如果是JobStoreSupport的话,那么就需要设置锁控制器,用于集群的调度同步  
  29.       if (js instanceof JobStoreSupport) {  
  30.           // Install custom lock handler (Semaphore)  
  31.           String lockHandlerClass = cfg.getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS);  
  32.           if (lockHandlerClass != null) {  
  33.               try {  
  34.                   Semaphore lockHandler = (Semaphore)loadHelper.loadClass(lockHandlerClass).newInstance();  
  35.   
  36.                   tProps = cfg.getPropertyGroup(PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true);  
  37.   
  38.                   // If this lock handler requires the table prefix, add it to its properties.  
  39.                   if (lockHandler instanceof TablePrefixAware) {  
  40.                       tProps.setProperty(  
  41.                               PROP_TABLE_PREFIX, ((JobStoreSupport)js).getTablePrefix());  
  42.                       tProps.setProperty(  
  43.                               PROP_SCHED_NAME, schedName);  
  44.                   }  
  45.   
  46.                   try {  
  47.                       setBeanProps(lockHandler, tProps);  
  48.                   } catch (Exception e) {  
  49.                       initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass  
  50.                               + "' props could not be configured.", e);  
  51.                       throw initException;  
  52.                   }  
  53.   
  54.                   ((JobStoreSupport)js).setLockHandler(lockHandler);  
  55.                   getLog().info("Using custom data access locking (synchronization): " + lockHandlerClass);  
  56.               } catch (Exception e) {  
  57.                   initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass  
  58.                           + "' could not be instantiated.", e);  
  59.                   throw initException;  
  60.               }  
  61.           }  
  62.       }  
获取datasource,可能多个:

   

[java]  view plain  copy
  1. String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);//获取多个dataSource,所以需要JTX分布式事务的支持,因为有多数据源的job存在的  
  2.         for (int i = 0; i < dsNames.length; i++) {  
  3.             PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(  
  4.                     PROP_DATASOURCE_PREFIX + "." + dsNames[i], true));  
  5.   
  6.             //先检测connectionProvider这种配置方式,本质上所有的datasource都会被封装为某种Provider,Provider是quartz对datasource的一中封装而已  
  7.             String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);  
  8.   
  9.   
  10.             // custom connectionProvider...  
  11.             if(cpClass != null) {  
  12.                 ConnectionProvider cp = null;  
  13.                 try {  
  14.                     cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();  
  15.                 } catch (Exception e) {  
  16.                     initException = new SchedulerException("ConnectionProvider class '" + cpClass  
  17.                             + "' could not be instantiated.", e);  
  18.                     throw initException;  
  19.                 }  
  20.   
  21.   
  22.                 try {//移除Provider这个配置后,把其他配置关联到provider  
  23.                     // remove the class name, so it isn't attempted to be set  
  24.                     pp.getUnderlyingProperties().remove(  
  25.                             PROP_CONNECTION_PROVIDER_CLASS);  
  26.   
  27.   
  28.                     setBeanProps(cp, pp.getUnderlyingProperties());  
  29.                     cp.initialize();  
  30.                 } catch (Exception e) {  
  31.                     initException = new SchedulerException("ConnectionProvider class '" + cpClass  
  32.                             + "' props could not be configured.", e);  
  33.                     throw initException;  
  34.                 }  
  35.                  
  36.                 //把所有的Datasource加到manager  
  37.                 dbMgr = DBConnectionManager.getInstance();  
  38.                 dbMgr.addConnectionProvider(dsNames[i], cp);  
  39.             } else {  
[java]  view plain  copy
  1. //查找Jndi这种配置  
  2. String dsJndi = pp.getStringProperty(PROP_DATASOURCE_JNDI_URL, null);  
  3.   
  4.   
  5. if (dsJndi != null) {  
  6.     boolean dsAlwaysLookup = pp.getBooleanProperty(  
  7.             PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP);  
  8.     String dsJndiInitial = pp.getStringProperty(  
  9.             PROP_DATASOURCE_JNDI_INITIAL);  
  10.     String dsJndiProvider = pp.getStringProperty(  
  11.             PROP_DATASOURCE_JNDI_PROVDER);  
  12.     String dsJndiPrincipal = pp.getStringProperty(  
  13.             PROP_DATASOURCE_JNDI_PRINCIPAL);  
  14.     String dsJndiCredentials = pp.getStringProperty(  
  15.             PROP_DATASOURCE_JNDI_CREDENTIALS);  
  16.     Properties props = null;  
  17.     if (null != dsJndiInitial || null != dsJndiProvider  
  18.             || null != dsJndiPrincipal || null != dsJndiCredentials) {  
  19.         props = new Properties();  
  20.         if (dsJndiInitial != null) {  
  21.             props.put(PROP_DATASOURCE_JNDI_INITIAL,  
  22.                     dsJndiInitial);  
  23.         }  
  24.         if (dsJndiProvider != null) {  
  25.             props.put(PROP_DATASOURCE_JNDI_PROVDER,  
  26.                     dsJndiProvider);  
  27.         }  
  28.         if (dsJndiPrincipal != null) {  
  29.             props.put(PROP_DATASOURCE_JNDI_PRINCIPAL,  
  30.                     dsJndiPrincipal);  
  31.         }  
  32.         if (dsJndiCredentials != null) {  
  33.             props.put(PROP_DATASOURCE_JNDI_CREDENTIALS,  
  34.                     dsJndiCredentials);  
  35.         }  
  36.     }  
  37.     JNDIConnectionProvider cp = new JNDIConnectionProvider(dsJndi,  
  38.             props, dsAlwaysLookup);  
  39.     dbMgr = DBConnectionManager.getInstance();  
  40.     dbMgr.addConnectionProvider(dsNames[i], cp);  
  41. else {  
[java]  view plain  copy
  1.         //检查local driver这种配置  
  2.         String dsDriver = pp.getStringProperty(PoolingConnectionProvider.DB_DRIVER);  
  3.         String dsURL = pp.getStringProperty(PoolingConnectionProvider.DB_URL);  
  4.   
  5.   
  6.         if (dsDriver == null) {  
  7.             initException = new SchedulerException(  
  8.                     "Driver not specified for DataSource: "  
  9.                             + dsNames[i]);  
  10.             throw initException;  
  11.         }  
  12.         if (dsURL == null) {  
  13.             initException = new SchedulerException(  
  14.                     "DB URL not specified for DataSource: "  
  15.                             + dsNames[i]);  
  16.             throw initException;  
  17.         }  
  18.         try {  
  19.             PoolingConnectionProvider cp = new PoolingConnectionProvider(pp.getUnderlyingProperties());  
  20.             dbMgr = DBConnectionManager.getInstance();  
  21.             dbMgr.addConnectionProvider(dsNames[i], cp);  
  22.         } catch (SQLException sqle) {  
  23.             initException = new SchedulerException(  
  24.                     "Could not initialize DataSource: " + dsNames[i],  
  25.                     sqle);  
  26.             throw initException;  
  27.         }  
  28.     }  
  29.   
  30.   
  31. }  

接下来还有SchedulerPlugins、JobListeners、TriggerListeners、ThreadExecutor等的配置。基本都大同小异,毕竟都是配置文件解析而已。

其中ThreadExecutor是执行池,主要是执行schedule 和refire任务。

然后初始化JobRunShellFactory,这个是一个封装执行Job的factory,主要是为了一些listener的执行和异常处理:

[java]  view plain  copy
  1. JobRunShellFactory jrsf = null// Create correct run-shell factory...  
  2.      
  3.            if (userTXLocation != null) {  
  4.                UserTransactionHelper.setUserTxLocation(userTXLocation);  
  5.            }  
  6.    //更具JTA的配置情况初始化特定的RunShellFactory  
  7.            if (wrapJobInTx) {  
  8.                jrsf = new JTAJobRunShellFactory();  
  9.            } else {  
  10.                jrsf = new JTAAnnotationAwareJobRunShellFactory();  
  11.            }  

 对于db JobStore的话是有一些处理的:

[java]  view plain  copy
  1. if (js instanceof JobStoreSupport) {  
  2.                JobStoreSupport jjs = (JobStoreSupport)js;  
  3.                jjs.setDbRetryInterval(dbFailureRetry);  
  4.                if(threadsInheritInitalizersClassLoader)  
  5.                    jjs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);  
  6.                  
  7.                jjs.setThreadExecutor(threadExecutor);//所以 ThreadExecutor也用来处理数据库的链接的(比如说定时重试)  
  8.            }  
  9.      

初始化以上对象和资源后,quartz会把他保存到QuartzSchedulerResources里面,所以你会看到代码的很多地方都有用到这个对象:

[java]  view plain  copy
  1. QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();  
  2.            rsrcs.setName(schedName);  
  3.            rsrcs.setThreadName(threadName);  
  4.            rsrcs.setInstanceId(schedInstId);  
  5.            rsrcs.setJobRunShellFactory(jrsf);  
  6.            rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);  
  7.            rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);  
  8.            rsrcs.setRunUpdateCheck(!skipUpdateCheck);  
  9.            rsrcs.setBatchTimeWindow(batchTimeWindow);  
  10.            rsrcs.setMaxBatchSize(maxBatchSize);  
  11.            rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown);  
  12.            rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait);  
  13.            rsrcs.setJMXExport(jmxExport);  
  14.            rsrcs.setJMXObjectName(jmxObjectName);  
Sheduler的初始化和设置在下面:

[java]  view plain  copy
  1. qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry);//实例化Scheduler  
  2.             qsInited = true;  
  3.       
  4.             // Create Scheduler ref...  
  5.             Scheduler scheduler = instantiate(rsrcs, qs);//封装QuartzScheduler为StdQuartzScheduler,其实<span style="font-family: Arial, Helvetica, sans-serif;">StdQuartzScheduler就是一个装饰模式而已,QuartzSch//eduler是没有实现Sheduler接口的</span>  
  6.   
  7.       
  8.             // set job factory if specified  
  9.             if(jobFactory != null) {  
  10.                 qs.setJobFactory(jobFactory);  
  11.             }  
  12.       
  13.             // Initialize plugins now that we have a Scheduler instance.  
  14.             for (int i = 0; i < plugins.length; i++) {  
  15.                 plugins[i].initialize(pluginNames[i], scheduler, loadHelper);  
  16.             }  
  17.       
  18.             // add listeners  
  19.             for (int i = 0; i < jobListeners.length; i++) {  
  20.                 qs.getListenerManager().addJobListener(jobListeners[i], EverythingMatcher.allJobs());  
  21.             }  
  22.             for (int i = 0; i < triggerListeners.length; i++) {  
  23.                 qs.getListenerManager().addTriggerListener(triggerListeners[i], EverythingMatcher.allTriggers());  
  24.             }  
  25.       
  26.             // set scheduler context data...  
  27.             for(Object key: schedCtxtProps.keySet()) {  
  28.                 String val = schedCtxtProps.getProperty((String) key);      
  29.                 scheduler.getContext().put((String)key, val);  
  30.             }  
  31.       
  32.             // fire up job store, and runshell factory  
  33.            //启动job  
  34.             js.setInstanceId(schedInstId);  
  35.             js.setInstanceName(schedName);  
  36.             js.setThreadPoolSize(tp.getPoolSize());  
  37.             js.initialize(loadHelper, qs.getSchedulerSignaler());//是一个回掉Job Scheduler的接口<span style="font-family: Arial, Helvetica, sans-serif;">SchedulerSignaler</span>  
  38.   
  39.            //启动jobRunShellFactory,<span style="font-family: Arial, Helvetica, sans-serif;">initialize方法就是标准的初始化方法,是quartz的代码习惯</span>  
  40.   
  41.             jrsf.initialize(scheduler);  
  42.             //启动sheduler  
  43.             qs.initialize();  
  44.       
  45.             getLog().info(  
  46.                     "Quartz scheduler '" + scheduler.getSchedulerName()  
  47.                             + "' initialized from " + propSrc);  
  48.       
  49.             getLog().info("Quartz scheduler version: " + qs.getVersion());  
  50.             //添加资源引用防止被垃圾回收  
  51.             // prevents the repository from being garbage collected  
  52.             qs.addNoGCObject(schedRep);  
  53.             // prevents the db manager from being garbage collected  
  54.             if (dbMgr != null) {  
  55.                 qs.addNoGCObject(dbMgr);  
  56.             }  


总结下来,其实挺简单的:读取配置文件,安装前缀的风格初始化各种类和属性,然后包装到 QuartzSchedulerResources 给Sheduler用,然后初始化:

jobStore、ThreadPool、JobRunShellFactory、ThreadExecutor、jobFactory、开启各种mananger、初始化Scheduler并为其添加pluger和listener,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值