2023-09-12  阅读(205)
原文作者:一直不懂 原文地址: https://blog.csdn.net/shenchaohao12321/article/details/98854225

1、LifeCycle接口概述

LifeCycle定义启动/停止生命周期控制方法的通用接口。这种情况的典型用例是控制异步处理。可以由两个组件(通常是Spring上下文中定义的Spring bean)和容器(通常是Spring ApplicationContext本身)实现。容器将开始/停止信号传播到每个容器内应用的所有组件。可用于通过JMX进行直接调用或管理操作,org.springframework.jmx.export.MBeanExporter通常使用org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler定义,从而限制活动控制组件对Lifecycle接口的可见性。
请注意,仅在顶级单例bean上支持当前的Lifecycle接口。在任何其他组件上,Lifecycle接口将保持未被检测到,因此将被忽略。另请注意,扩展的SmartLifecycle接口提供了与应用程序上下文的启动和关闭阶段的复杂集成。

2、SmartLifecycle接口

2.1、概述

SmartLifecycle是Lifecycle接口的扩展,用于那些需要在ApplicationContext按特定顺序刷新和/或关闭时启动的对象。 isAutoStartup()返回值指示是否应在上下文刷新时启动此对象。回调方法stop(Runnable)对于具有异步关闭过程的对象很有用。此接口的任何实现都必须在关闭完成时调用回调的run()方法,以避免整个ApplicationContext关闭中出现不必要的延迟。
此接口扩展了Phased,getPhase()方法的返回值指示应该启动和停止此Lifecycle组件的阶段。启动过程以最低相位值开始,以最高相位值结束(Integer.MIN_VALUE最低,Integer.MAX_VALUE最高)。关闭过程将应用相反的顺序。具有相同值的任何组件将在同一阶段中任意排序。
示例:如果组件B依赖于已经启动的组件A,则组件A的相位值应低于组件B.在关闭过程中,组件B将在组件A之前停止。
任何明确的“依赖”关系都优先于阶段顺序,因此依赖bean始终在其依赖之后启动,并始终在其依赖之前停止。
上下文中未实现SmartLifecycle的任何生命周期组件都将被视为具有0的阶段值。这样,SmartLifecycle实现可以在这些生命周期组件之前开始,如果它具有负相位值,或者可以在那些之后开始组件,如果它具有正相位值。
请注意,由于SmartLifecycle中的自动启动支持,SmartLifecycle bean实例通常会在应用程序上下文启动时初始化。因此,bean定义lazy-init标志对SmartLifecycle bean的实际影响非常有限。

2.2、类图

202309122024162331.png

2.3、方法说明

方法 描述
方法 描述
start()  bean初始化完毕后,该方法会被执行,对于容器,这会将启动信号传播到所有适用的组件。
stop()  通常以同步方式停止此组件,以便在返回此方法时组件完全停止。当需要异步停止行为时,请考虑实现SmartLifecycle及其stop(Runnable)变体。
isRunning() 检查此组件当前是否正在运行。对于容器,仅当应用的所有组件当前正在运行时,才会返回true。
getPhase()  返回此生命周期对象应运行的阶段。默认实现返回Integer.MAX_VALUE,以便在常规生命周期实现后执行停止回调。
isAutoStartup() 如果随ApplicationContext刷新时容器自动启动此Lifecycle组件时,则返回true。值false表示该组件旨在通过显式的start()调用启动,类似于普通的Lifecycle实现。默认实现返回true。
stop(Runnable)  spring容器发现当前对象实现了SmartLifecycle,就调用stop(Runnable),如果只是实现了Lifecycle,就调用stop()

3、LifecycleProcessor

用于在ApplicationContext中处理Lifecycle bean的策略接口。LifecycleProcessor接口有两个方法,下图显示了其调用流程。

202309122024165832.png

202309122024169323.png

前者在ApplicationContext刷新时调用,后再在ApplicationContext关闭时调用。

4、源码分析

4.1、容器启动流程

在Spring容器启动的时候会调用ApplicationContext的refresh方法,此方法在最后一个步骤是调用finishRefresh方法。

202309122024172874.png

这个方法中首先会实例化一个LifecycleProcessor:先从容器中找一个名为lifecycleProcessor的LifecycleProcessor否则使用DefaultLifecycleProcessor。下面是DefaultLifecycleProcessor的实现。

    @Override
    public void onRefresh() {
       startBeans(true);
       this.running = true;
    }
    private void startBeans(boolean autoStartupOnly) {
       // 单例非懒加载bean
       Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
       Map<Integer, LifecycleGroup> phases = new HashMap<>();
       lifecycleBeans.forEach((beanName, bean) -> {
          // 默认autoStartupOnly=true,因此只能筛选出是SmartLifecycle.isAutoStartup()=true的bean
          if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
             int phase = getPhase(bean);
             // 相同phases一组
             LifecycleGroup group = phases.get(phase);
             if (group == null) {
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
             }
             // 向group的members添加beanName, bean
             group.add(beanName, bean);
          }
       });
       if (!phases.isEmpty()) {
          List<Integer> keys = new ArrayList<>(phases.keySet());
          // phases从小到大
          Collections.sort(keys);
          for (Integer key : keys) {
             // 同属一个组的Lifecycle一起启动
             phases.get(key).start();
          }
       }
    }

上面代码是从容器中选出非懒加载单例的Lifecycle,DefaultLifecycleProcessor只筛选出SmartLifecycle.isAutoStartup()=true的bean,把相同phase的bean封装成一个组LifecycleGroup,这些组按照phase从小到大依次调用start方法。下面是其实现。

    public void start() {
       if (this.members.isEmpty()) {
          return;
       }
       if (logger.isDebugEnabled()) {
          logger.debug("Starting beans in phase " + this.phase);
       }
       Collections.sort(this.members);
       for (LifecycleGroupMember member : this.members) {
          doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
       }
    }
    private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
       // 移除已经执行过start方法的bean,因为下面依赖原因,避免重复调用
       Lifecycle bean = lifecycleBeans.remove(beanName);
       if (bean != null && bean != this) {
          // 依赖的bean也是Lifecycle先执行它的start方法
          String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
          for (String dependency : dependenciesForBean) {
             doStart(lifecycleBeans, dependency, autoStartupOnly);
          }
          // 需要是非运行状态且是isAutoStartup
          if (!bean.isRunning() &&
                (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
             if (logger.isTraceEnabled()) {
                logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]");
             }
             try {
                bean.start();
             }
             catch (Throwable ex) {
                throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
             }
             if (logger.isDebugEnabled()) {
                logger.debug("Successfully started bean '" + beanName + "'");
             }
          }
       }
    }

4.2、容器关闭流程

当Spring容器启动失败的时候会调用close()方法,当然主动调用也可以。

    @Override
    public void close() {
       synchronized (this.startupShutdownMonitor) {
          doClose();
          // If we registered a JVM shutdown hook, we don't need it anymore now:
          // We've already explicitly closed the context.
          if (this.shutdownHook != null) {
             try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
             }
             catch (IllegalStateException ex) {
                // ignore - VM is already shutting down
             }
          }
       }
    }

close方法会调用doClose方法,这个方法中会调用lifecycleProcessor.onClose();

202309122024176865.png

下面是DefaultLifecycleProcessor的实现代码:

    @Override
    public void onClose() {
       stopBeans();
       this.running = false;
    }
    private void stopBeans() {
       Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
       Map<Integer, LifecycleGroup> phases = new HashMap<>();
       lifecycleBeans.forEach((beanName, bean) -> {
          int shutdownPhase = getPhase(bean);
          LifecycleGroup group = phases.get(shutdownPhase);
          if (group == null) {
             group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
             phases.put(shutdownPhase, group);
          }
          group.add(beanName, bean);
       });
       if (!phases.isEmpty()) {
          List<Integer> keys = new ArrayList<>(phases.keySet());
          keys.sort(Collections.reverseOrder());
          for (Integer key : keys) {
             phases.get(key).stop();
          }
       }
    }
阅读全文
  • 点赞