通过源码查看Spring SmartLifecycle 的执行顺序

最新需要用到SmartLifecycle ,写了一个测试类,打印了一下执行顺序如下:

/**
 *
 *
 * @author cuiyt
 * @date: 2017年8月31日 上午8:47:54
 */
public class TestSmartLifecycle implements SmartLifecycle {

    private boolean isRunning = false;
    @Override
    public void start() {
        System.out.println("test start-------------------------");
        isRunning = true;
    }

    @Override
    public void stop() {
        System.out.println("test stop-------------------------");
        isRunning = false;

    }

    @Override
    public boolean isRunning() {
        System.out.println("test isRunning-------------------------");
        return isRunning;
    }

    @Override
    public int getPhase() {
        System.out.println("test getPhase-------------------------");
        return 0;
    }

    @Override
    public boolean isAutoStartup() {
        System.out.println("test isAutoStartup-------------------------");
        return true;
    }

    @Override
    public void stop(Runnable callback) {
        System.out.println("test callback-------------------------");
        isRunning = false;
    }

}

启动顺序



停止顺序



先来看启动顺序为什么执行了两次

test isAutoStartup-------------------------
test getPhase-------------------------

private void startBeans(boolean autoStartupOnly) {
        Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();//获取Lifecycle实现类的bean
        Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
        for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
            Lifecycle bean = entry.getValue();//判断是不是自动启动,这里调用了isAutoStartup
            if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
                int phase = getPhase(bean);//getPhase()方法内部调用了getPhase return (bean instanceof Phased ? ((Phased) bean).getPhase() : 0);
                LifecycleGroup group = phases.get(phase);
                if (group == null) {//如果相同启动顺序的不存在,则新new一个组,并将bean加入到这个组
                    group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                    phases.put(phase, group);
                }
                group.add(entry.getKey(), bean);//如果相同启动顺序的存在,则将bean加入到这个组            }     }      if (phases.size() > 0) {

        List<Integer> keys = new ArrayList<Integer>(phases.keySet());
        Collections.sort(keys);
        for (Integer key : keys) {
          phases.get(key).start();//获取所有Lifecyccle并分完组后,则开始真正的执行
      }
    }

接下来看执行的顺序

test getPhase-------------------------
test isRunning-------------------------
test isAutoStartup-------------------------
test start-------------------------

public void start() {
            if (this.members.isEmpty()) {
                return;
            }
            if (logger.isInfoEnabled()) {
                logger.info("Starting beans in phase " + this.phase);
            }
            Collections.sort(this.members);//这里进行了排序,查看LifecycleGroupMember的源码(见下面代码),发现他实现了Comparable接口,compareTo方法里面再次调用了getPhase()
      for (LifecycleGroupMember member : this.members) {               if (this.lifecycleBeans.containsKey(member.name)) {               doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); //调用doStart()          }       } }
    /**
     * Adapts the Comparable interface onto the lifecycle phase model.
     */
    private class LifecycleGroupMember implements Comparable<LifecycleGroupMember> {

        private final String name;

        private final Lifecycle bean;

        LifecycleGroupMember(String name, Lifecycle bean) {
            this.name = name;
            this.bean = bean;
        }

        @Override
        public int compareTo(LifecycleGroupMember other) {
            int thisOrder = getPhase(this.bean);
            int otherOrder = getPhase(other.bean);
            return (thisOrder == otherOrder ? 0 : (thisOrder < otherOrder) ? -1 : 1);
        }
    }

doStart()

/**
     * Start the specified bean as part of the given set of Lifecycle beans,
     * making sure that any beans that it depends on are started first.
     * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
     * @param beanName the name of the bean to start
     */
    private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
        Lifecycle bean = lifecycleBeans.remove(beanName);
        if (bean != null && !this.equals(bean)) {
            String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
            for (String dependency : dependenciesForBean) {
                doStart(lifecycleBeans, dependency, autoStartupOnly);
            }        //这里判断是否在运行,调用了isRunning(),isAutoStartup()
      if (!bean.isRunning() && (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {         if (logger.isDebugEnabled()) {           logger.debug("Starting bean ‘" + beanName + "‘ of type [" + bean.getClass() + "]");         }                 try {           bean.start(); //调用start()        } catch (Throwable ex) { throw new ApplicationContextException("Failed to start bean ‘" + beanName + "‘", ex); } if (logger.isDebugEnabled()) { logger.debug("Successfully started bean ‘" + beanName + "‘"); } } } }

停止顺序

test getPhase-------------------------
2017-08-31 09:06:57.581 INFO 11028 --- [on(2)-127.0.0.1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
test getPhase-------------------------
test isRunning-------------------------
test callback-------------------------

同样是先获取实现bean,并分组,调用了两次getPhase()

    private void stopBeans() {
        Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
        Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
        for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
            Lifecycle bean = entry.getValue();
            int shutdownOrder = getPhase(bean);//第一次getPhase()
            LifecycleGroup group = phases.get(shutdownOrder);
            if (group == null) {
                group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false);
                phases.put(shutdownOrder, group);
            }
            group.add(entry.getKey(), bean);
        }
        if (phases.size() > 0) {
            List<Integer> keys = new ArrayList<Integer>(phases.keySet());
            Collections.sort(keys, Collections.reverseOrder());
            for (Integer key : keys) {
                phases.get(key).stop();//开始停止
            }
        }
    }

stop方法

public void stop() {
            if (this.members.isEmpty()) {
                return;
            }
            if (logger.isInfoEnabled()) {
                logger.info("Stopping beans in phase " + this.phase);
            }
            Collections.sort(this.members, Collections.reverseOrder());//排序调用了一次getPhase()
      CountDownLatch latch = new CountDownLatch(this.smartMemberCount);       Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<String>());           for (LifecycleGroupMember member : this.members) {         if (this.lifecycleBeans.containsKey(member.name)) {             doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames); //调用doStop方法        } else if (member.bean instanceof SmartLifecycle) {               // already removed, must have been a dependent  latch.countDown(); } }           try { latch.await(this.timeout, TimeUnit.MILLISECONDS);                     if (latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isWarnEnabled()) {                   logger.warn("Failed to shut down " + countDownBeanNames.size() + " bean" + (countDownBeanNames.size() > 1 ? "s" : "")                 + " with phase value " + this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);           }         } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } }

doStop()

private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
            final CountDownLatch latch, final Set<String> countDownBeanNames) {

        Lifecycle bean = lifecycleBeans.remove(beanName);
        if (bean != null) {
            String[] dependentBeans = this.beanFactory.getDependentBeans(beanName);
            for (String dependentBean : dependentBeans) {
                doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
            }
            try {
                if (bean.isRunning()) {//判断是都还在运行,调用了isRunning()
                    if (bean instanceof SmartLifecycle) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Asking bean ‘" + beanName + "‘ of type [" + bean.getClass() + "] to stop");
                        }
                        countDownBeanNames.add(beanName);
                        ((SmartLifecycle) bean).stop(new Runnable() {//调用了stop(Runnable callback) 
                            @Override
                            public void run() {
                                latch.countDown();
                                countDownBeanNames.remove(beanName);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Bean ‘" + beanName + "‘ completed its stop procedure");
                                }
                            }
                        });
                    }
                    else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Stopping bean ‘" + beanName + "‘ of type [" + bean.getClass() + "]");
                        }
                        bean.stop();
                        if (logger.isDebugEnabled()) {
                            logger.debug("Successfully stopped bean ‘" + beanName + "‘");
                        }
                    }
                }
                else if (bean instanceof SmartLifecycle) {
                    // don‘t wait for beans that aren‘t running
                    latch.countDown();
                }
            }
            catch (Throwable ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Failed to stop bean ‘" + beanName + "‘", ex);
                }
            }
        }
    }
时间: 2024-10-23 07:26:55

通过源码查看Spring SmartLifecycle 的执行顺序的相关文章

通过源码理解Spring中@Scheduled的实现原理并且实现调度任务动态装载

前提 最近的新项目和数据同步相关,有定时调度的需求.之前一直有使用过Quartz.XXL-Job.Easy Scheduler等调度框架,后来越发觉得这些框架太重量级了,于是想到了Spring内置的Scheduling模块.而原生的Scheduling模块只是内存态的调度模块,不支持任务的持久化或者配置(配置任务通过@Scheduled注解进行硬编码,不能抽离到类之外),因此考虑理解Scheduling模块的底层原理,并且基于此造一个简单的轮子,使之支持调度任务配置:通过配置文件或者JDBC数据

通过源码了解ASP.NET MVC 几种Filter的执行过程

一.前言 之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了.其实阅读源码是个很好的习惯,它不只停留在知道怎么用的阶段,而是让我们知道一系列的为什么,为什么这样设计,为什么这样使用....很多朋友应该看过<asp.net x 框架揭秘>这本书,确实不错,特别是边看源码边看书,可以有不小的收获.Ok,我不是大神,我只是心血来潮想看一下源码! 二.几种常见的Filter

MYSQL Study案例之--通过源码安装Mysql-5.6

MYSQL  Study案例之--通过源码安装Mysql-5.6 系统环境: 操作系统:RedHat EL6 DB Soft:  Mysql 5.6.4-m7 1.系统环境 [[email protected] Packages]# uname -a Linux rh6 2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64 GNU/Linux [[email protected] Packag

Linux下通过源码编译安装程序

ASK: Linux下通过源码编译安装程序(configure/make/make install的作用) configure Linux 平台有各种不同的配置,安装时需要通过 configure 来确定,如:编译器用的是 cc 还是 gcc.不同库文件所在目录等.执行 configure 后会生成 Makefile,Makefile 规定了用什么编译器.编译参数等信息. make 根据 Makefile 中规定的内容进行编译,生成的可执行文件放在当前目录或某个子目录. make install

Ubuntu通过源码编译安装Octave 4.0

本教程/笔记,用于指导在Ubuntu及其他Linux系统上如何通过源码安装Octave. Octave简介 Octave是GNU旗下代替matlab的数学工具软件,语法与matlab高度兼容,并且支持一些独有的更清晰更符合Linux社区习惯的语法.虽然在一些具体工具包和部分特性和效率上不如matlab,但是对于一般用户,它是matlab的一个有效的合法的免费的替代工具. 3.8版本之前官方没有GUI界面,让想使用GUI,必须下载第三方的工具(如qtoctave). 3.8版本加入了实验性的GUI

Linux下通过源码编译GD库

因为之前都通过源码直接编译安装的lamp环境,所以好多扩展库都是没有安装的,突然现在要用到一个验证码类,imagecreate函数显示未定义,所以就来安装编译下GD库, 首先需要先安装 gd 前置库 : freetype ,jpegsrc,libpng. freetype wget "http://download.savannah.gnu.org/releases/freetype/freetype-2.4.0.tar.bz2" tar jxvf freetype-2.4.0.tar

【JDK源码分析】通过源码分析CyclicBarrier

前言 CyclicBarrier它是什么?一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点.类似于朋友之间联系要在中午聚个会,几个朋友全部到齐后才开始喝酒吃菜. 源码 CyclicBarrier属性和构造器 public class CyclicBarrier { // 互斥锁 private final ReentrantLock lock = new ReentrantLock(); // 条件等待 private final Condition trip = lock.new

通过源码分析MyBatis的缓存

看了通过源码分析MyBatis的缓存这篇文章后,自己跟着源码过了一遍,对mybatis的一级缓存和二级缓存有了更清楚的认识. 一级缓存是SqlSession级别的,同一个sqlSession在第二次执行一个相同参数的select语句并且第一次执行后没有对数据进行更新,就会直接从缓存取值,而不再进行查找.通过阅读源码了解了这个过程,首先org.apache.ibatis.session.defaults.DefaultSqlSession.select(String, Object, RowBou

Android 4.4 通过源码进行 root 操作

2019-05-28 关键字:rk root 笔者手里有一块运行着 Android4.4 操作系统的 rk3128 开发板.刚好还没 root 的,摸索了一方,找到一个可以成功 root 的方式,特此记录一下. 整个过程其实并没有网上说的这么复杂,就简单几步,照着做就好了. step 1 预置外部 su 程序进系统.这个 su 程序已经作为附件上传到网上了.下载链接如下 链接: https://pan.baidu.com/s/1dHBfJ-SipGx6rGbpuW-p6A 提取码: fda6 这