Quartz与Spring集成——启动调度器
来源:互联网 发布:四川省网络试听作品 编辑:程序博客网 时间:2024/05/19 18:12
前言
在《Quartz与Spring集成——创建调度器》一文中介绍了调度器的创建过程,本文将分析其启动过程。熟悉Spring原理的人都知道AbstractApplicationContext的refresh方法的重要性,在refresh方法中调用了finishRefresh方法,最后会调用到SchedulerFactoryBean的start方法,其调用栈如图1所示。
图1SchedulerFactoryBean的start方法的调用栈
根据图1的内容,我们知道spring容器初始化完毕的最后会启动所有的bean,SchedulerFactoryBean的start方法就是这时候被调用的。
启动调度器
SchedulerFactoryBean的start方法的实现见代码清单1所示。
代码清单1
@Overridepublic void start() throws SchedulingException {if (this.scheduler != null) {try {startScheduler(this.scheduler, this.startupDelay);}catch (SchedulerException ex) {throw new SchedulingException("Could not start Quartz Scheduler", ex);}}}
startScheduler方法的实现,见代码清单2。
代码清单2
protected void startScheduler(final Scheduler scheduler, final int startupDelay) throws SchedulerException {if (startupDelay <= 0) {logger.info("Starting Quartz Scheduler now");scheduler.start();}else {//此分支启动一个后台线程,sleep参数startupDelay指定的秒数后,再启动调度器(即调用scheduler.start()),主要用于延迟启动}}startScheduler方法中的第二个条件分支用于延迟启动调度器,即当参数startupDelay大于0时,启动一个后台线程,睡眠(sleep)参数startupDelay指定的秒数后,再启动调度器(即调用scheduler.start();)。由于实际上也是执行scheduler.start();故此没有列出其代码。
以默认的Scheduler实现类StdScheduler为例,其start方法的实现如下:
public void start() throws SchedulerException { sched.start(); }根据《Quartz与Spring集成——创建调度器》一文的内容我们知道,这里的sched实际是QuartzScheduler的实例,其start方法的实现见代码清单3。
代码清单3
public void start() throws SchedulerException { if (shuttingDown|| closed) { throw new SchedulerException( "The Scheduler cannot be restarted after shutdown() has been called."); } // QTZ-212 : calling new schedulerStarting() method on the listeners // right after entering start() notifySchedulerListenersStarting(); if (initialStart == null) { initialStart = new Date(); this.resources.getJobStore().schedulerStarted(); startPlugins(); } else { resources.getJobStore().schedulerResumed(); } schedThread.togglePause(false); getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " started."); notifySchedulerListenersStarted(); }
阅读代码清单3,整理启动QuartzScheduler的步骤如下:
- 启动前对关闭中(shuttingDown)、已关闭(closed)的状态校验,此时会抛出SchedulerException,避免进入不正确的状态;
- 通知所有对调度器监听的监听器——现在正在启动调度器,notifySchedulerListenersStarting方法的实现见代码清单4;
- 启动调度器,以LocalDataSourceJobStore为例,实际调用了其父类JobStoreSupport的schedulerStarted方法;
- 启动插件,startPlugins方法的实现见代码清单5;
- 调用QuartzSchedulerThread的togglePause方法(见代码清单6),其作用为在保证线程安全的前提下将paused设置为false,同时唤醒所有等待sigLock这个锁的线程。在《Quartz与Spring集成——创建调度器》一文中介绍QuartzSchedulerThread的启动的时候,曾经说过由于paused为true时导致不断轮询和等待sigLock。到这里QuartzSchedulerThread被唤醒后,run方法将挑出这个轮询继续执行,QuartzSchedulerThread的启动才真正开始;
- 通知所有对调度器监听的监听器——现在启动调度器已完成,notifySchedulerListenersStarted方法的实现见代码清单7;
代码清单4
public void notifySchedulerListenersStarting() { // build a list of all scheduler listeners that are to be notified... List<SchedulerListener> schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for (SchedulerListener sl : schedListeners) { try { sl.schedulerStarting(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of startup.", e); } } }
代码清单5
private void startPlugins() { java.util.Iterator<SchedulerPlugin> itr = resources.getSchedulerPlugins().iterator(); while (itr.hasNext()) { SchedulerPlugin plugin = itr.next(); plugin.start(); } }
代码清单6
void togglePause(boolean pause) { synchronized (sigLock) { paused = pause; if (paused) { signalSchedulingChange(0); } else { sigLock.notifyAll(); } } }
代码清单7
public void notifySchedulerListenersStarted() { // build a list of all scheduler listeners that are to be notified... List<SchedulerListener> schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners for(SchedulerListener sl: schedListeners) { try { sl.schedulerStarted(); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of startup.", e); } } }
启动JobStore
以LocalDataSourceJobStore为例,特别来分析下其schedulerStarted方法(见代码清单8)的实现,其处理步骤如下:
- 如果是集群部署,则创建集群管理器ClusterManager(直接继承了Thread,),并调用其initialize方法(见代码清单9)执行ClusterManager自身;
- 如果不是集群部署,则调用recoverJobs方法恢复任何失败的或者触发失常的作业;
- 创建MisfireHandler(也直接继承了Thread,用于恢复任何失败的或者触发失常的作业),并调用其initialize方法(见代码清单10)执行MisfireHandler自身;
代码清单8
public void schedulerStarted() throws SchedulerException { if (isClustered()) { clusterManagementThread = new ClusterManager(); if(initializersLoader != null) clusterManagementThread.setContextClassLoader(initializersLoader); clusterManagementThread.initialize(); } else { try { recoverJobs(); } catch (SchedulerException se) { throw new SchedulerConfigException( "Failure occured during job recovery.", se); } } misfireHandler = new MisfireHandler(); if(initializersLoader != null) misfireHandler.setContextClassLoader(initializersLoader); misfireHandler.initialize(); schedulerRunning = true; getLog().debug("JobStore background threads started (as scheduler was started)."); }
代码清单9
public void initialize() { this.manage(); ThreadExecutor executor = getThreadExecutor(); executor.execute(ClusterManager.this); }
代码清单10
public void initialize() { ThreadExecutor executor = getThreadExecutor(); executor.execute(MisfireHandler.this); }
小结
经过以上分析,对Quartz如何启动调度器的原理有了较深入的了解。前面说过当paused设置为false,QuartzSchedulerThread才正式启动,有关QuartzSchedulerThread的正式启动请阅读《Quartz与Spring集成——QuartzSchedulerThread的执行分析》一文。后记:个人总结整理的《深入理解Spark:核心思想与源码分析》一书现在已经正式出版上市,目前京东、当当、天猫等网站均有销售,欢迎感兴趣的同学购买。
京东:http://item.jd.com/11846120.html
当当:http://product.dangdang.com/23838168.html
1 0
- Quartz与Spring集成——启动调度器
- Quartz与Spring集成——创建调度器
- Quartz与Spring集成——创建调度器 定时
- Quartz与Spring集成——创建调度器
- Spring集成Quartz任务调度
- Spring与Quartz集成配置实现简单定时任务调度
- Spring与Quartz集成配置实现简单定时任务调度
- Quartz任务调度器与spring整合
- Quartz与Spring集成
- Spring进阶-怎样集成定时调度Quartz
- Spring集成quartz任务调度框架
- Spring集成Quartz定时调度时间配置
- Quartz与Spring集成—— SchedulerFactoryBean的初始化分析
- Quartz与Spring集成——QuartzSchedulerThread的执行分析
- Spring quartz 任务调度器 启动加载,定时加载
- Spring—Quartz定时任务调度
- 任务调度quartz(一)quartz在spring中的集成
- Quartz与Spring的集成
- 转载:C++ 实现银行排队服务模拟
- CodeForces 660A Co-prime Array
- 上传应用程序编译时报错:clang: error: unable to execute command: Segmentation fault: 11
- iOS 使用AFNetworking 3.1.0如何在请求头中加入cookie
- L3-001. 凑零钱-PAT团体程序设计天梯赛GPLT(01背包,动态规划)
- Quartz与Spring集成——启动调度器
- 以@为间隔,每5个字符为间距,分隔字符串
- Android6.0运行时权限解决方案
- android调用系统相机拍照与打开相册选择照片进行截取保存笔记
- 为View控件绑定监听器
- JavaScript强化教程-cookie对象
- 说说二进制
- shell,console,terminal / DOS、CMD的区别
- CSS伪类伪元素详解