scheduler初始化
先看个图:
- 1. SchedulerFacotory是一个接口,它有两个实现,StdSchedulerFacotory根据配置文件来创建Scheduler,DirectSchedulerFactory 主要通过编码对Scheduler控制,通常为了侵入性更小、实现更方便我们用StdSchedulerFacotory类型来创建StdScheduler,quartz.properties里面的配置都对应到这个StdSchedulerFactory中,所以对某个配置不明白已经该配置的默认值可以看StdSchedulerFactory中获取配置的代码。
- 2. 初始化流程第一步就是加载配置文件,第二步就是根据配置项创建各种对象。
public Scheduler getScheduler() throws SchedulerException {
// 第一步:加载配置文件,System的properties覆盖前面的配置
if (cfg == null) {
initialize();
}
SchedulerRepository schedRep = SchedulerRepository.getInstance();
Scheduler sched = schedRep.lookup(getSchedulerName());
if (sched != null) {
if (sched.isShutdown()) {
schedRep.remove(getSchedulerName());
} else {
return sched;
}
}
// 第二步:初始化,生成scheduler
sched = instantiate();
return sched;
}
- 3. 从第二步开始开代码,工厂调用getScheduler()方法后进入instantiate()方法,开始就会看到很多需要初始化的对象,下面代码都是在 instantiate()方法 中:
//需要创建获取的属性在这边
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;
- 4.上图中第5步是个重头戏,看代码,里面初始化了很多东西,线程也是在这里面起的,选几个核心的代码看看:
创建线程池:
// 创建线程池,这个在配置文件里面配线程池类名
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;
}
创建jobStore:
// 创建jobStore, 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;
}
创建其他对象都一样,根据配置文件配的类名称用反射创建对象。
最后把上面创建的对方放到QuartzSchedulerResources中并把线程池起来,这个相当于 QuartzScheduler 的资源存放处,如下:
QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();
rsrcs.setName(schedName);
rsrcs.setThreadName(threadName);
rsrcs.setInstanceId(schedInstId);
rsrcs.setJobRunShellFactory(jrsf);
rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);
rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);
rsrcs.setRunUpdateCheck(!skipUpdateCheck);
rsrcs.setBatchTimeWindow(batchTimeWindow);
rsrcs.setMaxBatchSize(maxBatchSize);
rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown);
rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait);
rsrcs.setJMXExport(jmxExport);
rsrcs.setJMXObjectName(jmxObjectName);
//这个线程执行者用于后面启动调度线程
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);
总体的逻辑是根据配置文件相关设置创建线程池,调度,jobstore等对象,然后都存放到quartzSchedulerResources,后续quartzScheduler需要用到上面对象都是通过quartzSchedulerResources操作。
scheduler 使用
以我们常用的scheduleJob(JobDetail jobDetail, Trigger trigger)方法来说明 scheduler 内部调用流程,如下图:
quartzScheduler都是通过quartzSchedulerResources获取jobStore,然后把任务和触发器放到jobStore中,后面调度线程会对JobStore中任务进行调度。