本章閱讀收獲:可了解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)容配喳,但還是覺得心里不爽,說了那么多凳干,其實就是不想讓那些跟我一樣的人(好吧晴裹,其實就是我自己)心里不爽而已~~~~