Spring 之 Lifecycle 及 SmartLifecycle

1 Lifecycle接口

最近在看Eureka源码,本想快速解决这场没有硝烟的战役,不曾想阻塞性问题一个接一个。为正确理解这个框架,我不得不耐着性子,慢慢梳理这些让人困惑的点。譬如本章要梳理的LifecycleSmartLifecycle。它们均为接口,其中后者继承于前者,他们的类图如下所示:

关于Lifecycle,网络平台给出的解释是这样的:它是Spring框架中的一个基础接口,用于简化管理有状态的组件(譬如连接池、定时任务等)的初始化、启动、停止等生命周期过程。它定义了以下核心方法

  • start():启动组件。这通常涉及初始化必要的资源,使组件处于可操作状态。
  • stop():停止组件。执行必要的清理工作,释放资源,使组件处于不可操作状态。
  • isRunning():该方法用于检查组件当前是否正在运行。返回true表示组件已启动且正在运行,返回false则表示未启动或已停止。

与SmartLifecycle相比,Lifecycle接口较为简单,不涉及启动顺序控制、自动启动配置或生命周期回调等功能。它是更基础的生命周期管理接口,适用于那些不需要复杂生命周期管理逻辑的组件

下面就一起看一下Spring的这个组件是如何使用的,其实非常简单,就是实现这个接口且实现其中定义的接口方法,比如下面这个自定义实现类:

package org.com.chinasoft.lifecycle;

import org.springframework.context.Lifecycle;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyLifecycle implements Lifecycle {
    /**
     * A 组件的运行状态
     */
    private volatile boolean running = false;
    /**
     * 容器启动后调用
     */
    @Override
    public void start() {
        System.out.println("lifecycle 容器启动完成,启动A组件...");
        running = true;
    }
    /**
     * 容器停止时调用
     */
    @Override
    public void stop() {
        System.out.println("lifecycle 收到关闭容器的信号,关闭A组件...");
        running = false;
    }
    /**
     * 检查此组件是否正在运行。
     * 1. 只有该方法返回false时,start方法才会被执行。
     * 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
     */
    @Override
    public boolean isRunning() {
        System.out.println("lifecycle 检查A组件的运行状态:" + running);
        return running;
    }
}

这个类是如何使用的呢通过显式调用ConfigurableApplicationContext上的start()/stop()方法实现的。具体可以看一下下面这个类:

package org.com.chinasoft;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(exclude = KafkaAutoConfiguration.class)
public class EurekaServiceApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(EurekaServiceApplication.class, args);
        ctx.start();
        ctx.stop();
    }

}

为什么可以这样呢?这是由于ConfigurableApplicationContext接口继承了Lifecycle接口,关于这个接口的继承结构可以看一下下面这幅图:

从图中可以很清楚的看到ConfigurableApplicationContext接口继承了Lifecycle接口,由此所有实现该接口的类都拥有了Lifecycle的功能。就像案例中写的那样,为了演示Lifecycle接口的用法,我们显式的调用ConfigurableApplicationContext对象上的start()和stop()方法。执行结果如下图所示:

这里既然提到了显式调用,那如果不显式调用是不是会不一样?(网络资料是这样讲的:如果不显式调用不会有图片中的输出)。注释上述调用代码后的执行结果如下图所示:

个人觉得这里就有点意思了,实际应用过程中,我们会显式调用这个吗?如果不会,这个调用的逻辑又在哪里呢?为了了解这个过程,还是先来看一下显式调用的执行流程(红色加粗加下划线的部分即为实际的执行流程):

  1. AbstractApplicationContext#start()【这个实现方法来自于其实现的Lifecycle接口】
  2. AbstractApplicationContext#getLifecycleProcessor()【调用这个方法的主要目的是获取Lifecycleprocessor对象,这个对象的实际类型为DefaultLifecycleProcessor】
  3. DefaultLifecycleProcessor#start()【调用该类中的start()方法。这个start()方法接着会调用DefaultLifecycleProcessor类上的startBeans()方法。这个方法首先从容器中拿到所有实现Lifecycle的bean,然后遍历这个集合,将拿到的bean对象包装到Map<Integer, LifecycleGrop>集合中(这个集合的value是一个LifecycleGroup对象),接着会不断调用LifecycleGroup对象的add()方法将Lifecycle对象的名字及对象添加到LifecycleGroup对象中实际类型为List的members集合中,注意这个集合中元素的实际类型为LifecycleGroupMember。最后遍历Map<Integer, LifecycleGrop>集合,然后调用LifecycleGroup对象上名为start()的方法,这个方法首先判断members元素是否为空,如果不为空则排序,然后遍历集合对象中的元素(LifecycleGroupMember),这个遍历会首先对要处理的元素进行检查,看其是否在LifecycleGroup对象上的lifecycleBeans集合中,如果在,则调用DefaultLifecycleProcessor类上的doStart()方法,如果一切顺利最后就调用Lifecycle实现类上的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);
       }
       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();
          }
          catch (Throwable ex) {
             throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
          }
          if (logger.isDebugEnabled()) {
             logger.debug("Successfully started bean '" + beanName + "'");
          }
       }
    }
}

实际调用跟踪过程中发现,这个方法中Lifecycle类型的对象bean是一个代理对象。难道说所有实现该Lifecycle接口的对象都是通过动态代理的方式注入到了Spring容器中?关于这个问题暂且不表,先来看一下这个处理过程中用到的几个类:

  • DefaultLifecycleProcessor,这是一个实现了LifecycleProcessor接口(这个接口继承了Lifecycle接口)和BeanFactoryAware接口的类。就测试案例中的操作来说:容器中所有对Lifecycle对象的操作都是通过这个类实现的。个人理解这个类的主要作用是:处理Spring Bean的生命周期。(大模型给出的解释:该类是一个实现LifecycleProcessor和BeanFactoryAware接口的Java类。LifecycleProcessor接口定义了在Spring应用程序上下文中处理生命周期方法的策略,BeanFactoryAware接口允许类在被Spring容器实例化时获取对BeanFactory的引用。这个类的作用是处理Spring Bean的生命周期。)
  • LifecycleGroup,它是DefaultLifecycleProcessor类中的一个私有内部类,其拥有的属性非常清晰:int类型的phase、long类型的timeout、boolean类型的autoStartupOnly、int类型的smartMemberCount、Map<String, ? extneds Lifecycle>类型的lifecycleBeans以及List<LifecycleGroupMember>类型的members。其中members用于存放包装了Lifecycle对象的LifecycleGroupMember对象。另外这个类上还有add(String name, Lifecycle bean)方法、start()方法和stop()方法。其中第一个方法用于将Lifecycle对象添加到members集合中,这个方法在添加前会判断这个对象是否是SmartLifecycle类型,如果是则将smartMemberCount的值自增1。start()方法的作用是在真正调用Lifecycle对象的start()方法前,做一些特殊处理,比如校验(this.members.isEmpty())、对集合进行排序(Collections.sort(this.members))、遍历members集合(调用DefaultLifecycleProcessor类上的doStart()方法,触发Lifecycle对象上start()方法的调用)。stop()方法的处理逻辑与start()方法基本类似,有兴趣的可以看一下源码。个人理解这个类的主要作用就是对Lifecycle类型的对象做个分组,以方便管理,实现一些特殊功能
  • LifecycleGroupMember,它与LifecycleGroup类似,都是DefaultLifecycleProcessor类中的一个私有内部类,这个类实现了Comparable接口,可以实现排序。这个类中有两个属性,一个为String类型的name,一个是Lifecycle类型的bean,其中只有一个compareTo()方法,这个方法是实现排序的关键。个人理解这个类的作用就是让系统中的Lifecycle对象具有排序功能

现在让我们一起回过头来看一下这个问题:实际应用过程中,我们会显式调用这个吗?如果不会,这个调用的逻辑又在哪里呢?注意这个问题中提到的显式调用,说的是Lifecycle接口中的start()及stop(),为了寻找这两个方法的调用起点,我们可以利用一下拥有强大查找功能的集成工具idea。通过idea的查找工具,我们可以发现调用Lifecycle接口中的start()及stop()方法的地方有以下几个:

  1. AbstractDiscoveryLifecycle的第243行this.start():AbstractDiscoveryLifecycle类实现了DiscoveryLifecycle接口(这个接口继承了SmartLifecycle接口,其中SmartLifecycle接口又继承了Lifecycle接口)。因此这里调用的就是AbstractDiscoveryLifecycle类中的start()方法,而这个方法的源调用方即ApplicationListener接口实现类AbstractDiscoveryLifecycle中的onApplicationEvent()方法
  2. RestartEndpoint的第203行this.context.start():ConfigurableApplicationContext类对象是RestartEndpoint中的属性,而这个类又实现了Lifecycle接口,所以这一行调用的其实就是ConfigurableApplicationContext类父类AbstractApplicationContext中的start()方法
  3. EurekaDiscoveryClientConfiguration的第76行this.autoRegistration.start():这个调用最终调用的是EurekaAutoServiceRegistration类中的start()方法(这个类实现了SmartLifecycle接口
  4. EurekaAutoServiceRegistration的第126行start():EurekaAutoServiceRegistration实现了SmartLifecycle接口,所以这个start()方法中做了一些自己的逻辑
  5. AbstractApplicationContext的第1303行getLifecycleProcessor().start():这个就是前面梳理的显式调用的入口
  6. DefaultLifecycleProcessor的第175行bean.start():这个前面也梳理过,调用的就是Lifecycle实现类上的start()方法

上述几个调用点的相关信息,可以参见下面这幅图,从图中我们可以看到上面罗列的所有调用点:

很遗憾,通过这次梳理,我们并未如愿找到显式调用的地方。但在这个过程中我们会发现有很多实现SmartLifecycle接口的类,比如前面梳理出来的EurekaAutoServiceRegistration类和AbstractDiscoveryLifecycle类。下面我们就来看一下SmartLifecycle接口的用法及其和Lifecycle接口的区别吧。

2 SmartLifecycle接口

前一小节介绍过SmartLifecycle接口继承了Lifecycle接口,所以这个接口的用法和Lifecycle接口的用法类似,使用时需要实现这个接口,并对其中的方法进行实现。这个接口中的方法主要有:

  1. start(): 用于启动组件。在应用上下文刷新后,所有实现了 SmartLifecycle 的 Bean 将按顺序调用此方法。如果组件已经启动,则不应抛出异常。
  2. stop(): 用于停止组件。可以是同步或异步的,具体取决于实现。如果组件需要异步停止,可以重写 stop(Runnable callback) 方法,并在完成时调用 callback.run()。
  3. isRunning(): 返回一个布尔值,表示组件当前是否正在运行
  4. getPhase(): 返回一个整数,表示此 Lifecycle 对象的启动和停止阶段。数值越小,优先级越高,启动越早,停止越晚。

通过上面的描述我们可以看出,SmartLifecycle接口具有以下几个特征:1.支持阶段(Phase)属性【通过getPhase()方法返回的阶段值,我们可以控制不同SmartLifecycle实现之间的启动和停止顺序。默认情况下,如果没有指定,阶段值为Integer.MAX_VALUE,意味着最后启动,最先停止。可以通过返回不同的整数值来改变这个顺序】;2.支持异步【如果我们的组件需要异步启动或停止,可以覆盖stop(Runnable callback)方法,Spring会在调用stop()时传入一个回调对象,你应该在实际操作完成时调用这个回调,以便框架知道何时继续处理其他生命周期事件】。

在实际工作中,使用SmartLifecycle接口来管理Spring Bean的生命周期,通常涉及以下几个步骤:

  1. 实现 SmartLifecycle 接口。首先,创建一个新的类实现SmartLifecycle接口。这个类将包含你的启动、停止逻辑以及生命周期管理的其他必要方法。
  2. 配置自动启动。默认情况下,实现了SmartLifecycle的Bean会自动启动,除非isAutoStartup()返回false。下述示例中,由于我们没有重写isAutoStartup(),因此默认为true,意味着当Spring容器启动时,此Bean将自动开始其生命周期。
  3. 注册到Spring容器。确保自定义的SmartLifecycle实现类被Spring扫描并注册为Bean。你可以使用@Component注解(如上例所示),或者在XML配置文件中声明。
  4. 控制启动和停止顺序。通过getPhase()方法可以控制Bean的启动和停止顺序。较低的阶段值优先启动和后停止,较高的阶段值则反之。
  5. 异步停止处理。在stop(Runnable callback)方法中,确保在所有清理和关闭操作完成后调用callback.run(),以便Spring容器知道停止操作已完成。
  6. 测试。启动Spring应用,观察控制台输出或使用日志记录来确认自定义的SmartLifecycle实现是否按照预期启动和停止。

 通过以上步骤,我们就可以有效地利用SmartLifecycle接口来管理复杂的启动和关闭流程,确保服务组件按需有序地运行。下面是一个简单的SmartLifecycle实现示例:

import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

@Component
public class MyServiceLifecycle implements SmartLifecycle {
    private volatile boolean running = false;
    @Override
    public void start() {
        // 在这里编写启动逻辑,比如启动线程、初始化连接等
        running = true;
        System.out.println("MyService started.");
    }
    @Override
    public void stop() {

    }
    @Override
    public boolean isAutoStartup() {
        return true;
    }
    @Override
    public void stop(Runnable callback) {
        // 执行停止逻辑,然后调用callback.run()通知Spring容器停止操作已完成
        running = false;
        System.out.println("MyService stopping...");
        // 假设这是一个模拟的异步停止操作
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟关闭过程
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                callback.run(); // 关闭完成,通知Spring
                System.out.println("MyService stopped.");
            }
        }).start();
    }
    @Override
    public boolean isRunning() {
        return running;
    }
    @Override
    public int getPhase() {
        // 返回启动顺序的阶段,默认是Integer.MAX_VALUE,可以根据需要调整
        return 0; // 设置为0,意味着该组件将尽可能早地启动
    }
}

上述SmartLifecycle实现类在程序启动后的执行结果如下图所示(图中左侧小角部分展示了系统停止时的输出,右侧则展示了启动时的输出):

梳理到这里我很好奇这个类时怎么被启动的,关于这个问题可以结合前一小节的相关梳理来理解。前一小节介绍过Lifecycle实现类的调用起点位于AbstractApplicationContextstart()方法中,不过这个是由我们手动调起的。在上一小节也介绍过这个方法最终会调用到LifecycleProcessor接口实现类DefaultLifecycleProcessor类中的start()方法中,后续这个方法的处理逻辑就是调用DefaultLifecycleProcessor类上的startBeans()方法。接着这个方法继续调用LifecycleGroup类上的start()方法。这个方法继续调用DefaultLifecycleProcessor类上的doStart()方法。这个方法最终会调用Lifecycle及SmartLifecycle实现类上的start()方法。不过,在代码中,我们并未像第一小节那样手动调用AbstractApplicationContextstart()方法,那此时容器又是如何调用我们自定义的Lifecycle及SmartLifecycle的实现类中的方法呢?通过运行时跟踪可以发现,这个调用链路是这样的:

  • AbstractApplicationContext#refresh():这个方法的最后会调用finishRefresh()方法
  • AbstractApplicationContext#finishRefresh():这个方法首先会调用initLifecycleProcessor()方法初始化AbstractApplicationContext 类上的lifecycleProcessor属性【注意:这个方法首先会看容器中是否存在名字为lifecycleProcessor的LifecycleProcessor对象,如果存在则直接用容器中的对象来初始化;如果不存在,则通过new方法创建一个DefaultLifecycleProcessor对象,并用其来完成初始化,同时像容器中注册一个名字为lifecycleProcessor的LifecycleProcessor对象】。接着这个方法会调用AbstractApplicationContext 类上的getLifecycleProcessor()方法获取AbstractApplicationContext 类上的lifecycleProcessor属性,并调用这个属性上的onRefresh()方法。下面的流程就和上一小节介绍的流程一致了,这里不再赘述,有兴趣的可以浏览一下前一小节的介绍。【这里备注一下:在跟踪代码时,initLifecycleProcessor()方法被执行了两次,也就是说AbstractApplicationContext类上的refresh()方法被执行了两次,具体原因暂时不知。后续会继续跟进

通过上面的介绍我们了解了容器启动过程中LifecycleProcessor的初始化及Lifecycle和SmartLifecycle接口实现类的调用流程。上一小节也提到了执行过程的一些细节,但终是过于粗糙,本小节我们再来梳理一下,以便加深理解。下面直接从DefaultLifecycleProcessor类的startBeans(boolean autoStartupOnly)方法开始分析。这个方法会从容器中拿到所有实现了Lifecycle接口的类对象,在本次实验中总共获取到了6个对象,具体如下图所示:

程序接下来遍历这个集合对象(首先判断autoStartupOnly对象的值——!autoStartupOnly,如果这个值为false,则进入if分支。如果不是就判断从集合中拿到的Lifecycle接口对象是否是SmartLifecycle类型,如果是要再判断这个对象是否自动启动,如果是,则直接进入if分支处理从集合中拿到的Lifecycle接口对象。处理逻辑是这样的:1.先调用这个对象上的getPhase()方法,得到一个值;2.从phases集合中拿到1中获取的值对应的LifecycleGroupdui对象,如果拿到的对象为空,则直接创建一个LifecycleGroup对象,并且将这个对象放到phases集合中,然后再将拿到的SmartLifecycle对象放到LifecycleGroup对象中。虽然对这段逻辑我还不太理解,但大概有了一点想法:前面讲过SmartLifecycle接口的实现类都有一个优先级,这个优先级可以通过getPhase()方法获得,这个方法返回的数值越小,优先级就越高,启动的就越早,停止的就越晚。反之,则启动的越晚,停止的越早。由于容器中可能存在具有相同优先级的SmartLifecycle对象,为了便于对这些对象进行管理,我们可以通过LifecycleGroup对象来管理(LifecycleGroup对象中有个List<LifecycleGroupMember>型的members属性,它就是用SmartLifecycle对象的,当然这个对象被包装成了LifecycleGroupMember对象)。属于同一个LifecycleGroup对象的SmartLifecycle对象具有相同的优先级。下面看一下从容器中拿到的6个Lifecycle接口对象经过循环后的最终处理结果:

下面我们看上图最后一部分代码,如果phases集合不为空,则执行if分支逻辑,这里程序会先拿到phases集合中的key集合【即下图代码中的keys变量】,然后对拿到的这个集合进行排序,接着遍历这个集合中的数据【注意这个集合最终的顺序是:从小到大,这也刚好印证了前面的说法——getPhase()方法返回的数值越小,优先级就越高,启动的就越早,停止的就越晚(这一句要看stop方法的处理逻辑,有兴趣的可以自己看一下)】,执行详情可以参见下面这幅图片:

接着程序会从phases集合中拿到key对应的LifecycleGroup对象,并调用这个对象上的start()方法,这个方法会判断当前对象(LifecycleGroup对象)上的members集合是否为空,如果不为空,则遍历这个集合并最终调用Lifecycle对象上的start()方法。梳理到这里我想还是先看前一节介绍的几个关键类的类结构图会好点,因为图片展示有时候比文字描述具有更好的效果:

下面再来看一下DefaultLifecycleProcessor类中的doStart()方法,这个方法是一个递归调用的方法,具体代码如下所示:

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
    Lifecycle bean = lifecycleBeans.remove(beanName);
    // 判断当前要执行的对象是否事是从lifecycleBeans集合中拿到的,如果不是,则跳过执行,否则进入if分支执行
    if (bean != null && !this.equals(bean)) {
       // 提取当前SmartLifecycle对象的依赖对象
       String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
       for (String dependency : dependenciesForBean) {
          // 递归调用doStart()方法
          doStart(lifecycleBeans, dependency, autoStartupOnly);
       }
       // 通过一系列判断后,如果合法,则调用SmartLifecycleBean对象上的start()方法
       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();
          }
          catch (Throwable ex) {
             throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
          }
          if (logger.isDebugEnabled()) {
             logger.debug("Successfully started bean '" + beanName + "'");
          }
       }
    }
}

关于这段代码的执行详情可以参见下面这幅图片(图片中被执行的SmartLifecycle对象是org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration,其依赖类有3个,它们分别为: AnnotationConfigEmbeddedWebApplicationContext |eurekaServiceRegistry |eurekaRegistration。它们3个均不在lifecycleBeans集合中,所以递归调用doStart()方法不会执行任何代码)

至此,我们将SmartLifecycle接口的相关知识梳理完了。不过,这只是其中的一部分,后续如有新的感悟,我还会持续跟进。

3 总结

通过前面的梳理,我了解了Spring框架提供Lifecycle接口的意义及用法,同时也明白SmartLifecycle是Lifecycle接口的子接口,只不过这个接口提供了更加强大的功能。譬如:

  1. 精细化的生命周期管理:它提供了比基本Lifecycle接口更细致的控制能力,允许开发者精确控制bean的启动顺序、运行状态判断及优雅停机流程。这对于构建复杂应用系统,特别是那些需要在应用上下文初始化后执行额外操作或维护长期运行服务的场景至关重要。
  2. 异步支持:通过stop(Runnable callback)方法,SmartLifecycle支持异步停止逻辑,使得资源清理或服务停止操作可以在不阻塞应用上下文关闭进程的情况下进行,提高了应用的响应性和灵活性。
  3. 自动启动配置:isAutoStartup()方法允许开发者定义某个组件是否应该随着Spring容器的启动而自动开始其生命周期,增加了使用的便利性和可配置性。
  4. 阶段化启动与停止:getPhase()方法定义了组件启动和停止的顺序,使得多个组件之间可以有明确的依赖关系和执行顺序,这对于确保系统服务的正确初始化和关闭顺序非常关键。
  5. 状态判断:isRunning()方法让框架和其他组件能够查询某个服务是否正在运行,这对于依赖状态逻辑控制或健康检查等场景非常有用。

那这两个接口之间究竟有什么异同呢?Lifecycle接口是Spring提供的一个扩展点,使得程序员可以利用这个接口在Spring容器启动或者关闭的时候,做一些自己需要的事情,譬如初始化数据库连接池等。这个接口提供了三个方法:start()、stop()、isRunning()。不过这个接口有个缺点:需要显式调用才能触发。SmartLifecycle接口也是Spring提供的一个扩展点,它继承了Lifecycle接口。相比Lifecycle接口,SmartLifecycle接口多提供了三个方法,它们分别为:isAutoStartup()、stop(Runnable)、getPhase()。另外相比前者,这个接口实现类的启动是在容器启动时自动调用的

下面再来回顾一下Lifecycle及SmartLifecycle接口的执行流程,由于前面已经详细梳理了启动流程,这里我们以停止流程为例来梳理,其执行的具体过程为:

  1. SpringApplication#run(String... args)
  2. SpringApplication#refreshContext(ConfigurableApplicationContext context)
  3. AbstractApplicationContext#registerShutdownHook(),这个方法会判断当前对象上的shutdownHook是否为空,如果为空,则会向容器中注册一个【这是一个单独的线程,线程中调用了AbstractApplicationContext中的doClose()方法】
  4. AbstractApplicationContext#doClose()
  5. AbstractApplicationContext#getLifecycleProcessor(),之后调用DefaultLifecycleProcessor类上的onClose()
  6. DefaultLifecycleProcessor#stopBeans(),这里会创建LifecycleGroup对象,然后将具有相同启动级别的SmartLifecycle对象添加进去,最后调用LifecycleGroup上的stop()方法
  7. DefaultLifecycleProcessor#doStop(Map<String, ? extends Lifecycle> lifecycleBeans,final String beanName,final CountDownLatch latch,final Set<String> countDownBeanNames),这里跟doStart()方法一样,也存在递归调用
  8. SmartLifecycle接口实现类上的stop()

好了今天的梳理就到这里吧。通过这次的梳理,我对Lifecycle和SmartLifecycle接口的理解更深了,相信在以后的工作中自己可以很灵活的运用其解决实际业务问题。不过这篇文章也为自己留下了一些未知之谜:

  • Lifecycle、SmartLifecycle实现类是如何注册到容器中的?
  • Spring容器中的钩子又是怎么回事?SpringApplication类的refreshContext(ConfigurableApplicationContext)方法中会根据registerShutdownHook的值来决定是否向容器中注入shutdownHook。这个注册操作是在AbstractApplicationContext 类的registerShutdownHook()方法中完成的,这个钩子是一个后台线程。关于这个还有一个疑问:这个钩子是何时触发执行的呢?
  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器挖掘工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值