Spring容器系列-启动原理(下)

Spring容器系列-启动原理(下)

   从上一篇文章《Spring容器系列-启动原理(上)》中,介绍了Spring容器初始化的核心方法refresh()的整体情况。这篇文章来详细展开介绍。其中比较重要的方法会标记上***

   一、refresh中的12个方法

   1.  prepareRefresh

   主要作用:记录下容器启动时间,标记"已启动"状态

   2. obtainFreshBeanFactory ***

   主要作用:创建bean工厂,如果已经有则销毁,没有则创建。将配置文件解析成一个个 Bean 定义,注册到 BeanFactory中。

   里面实现对beanDefinition的装载(说到底核心是一个key为beanName,value为beanDefinition的 map)

1 //用于保存BeanDefinition
2 //key:beanName value:BeanDefinition
3 
7 private final Map<string,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

   下面根据代码进行说明:    

    refresh()中通过obtainFreshBeanFactory()去解析 xml 文件,并且创建 BeanFactory(获取到的是DefaultListableBeanFactory类的实例)。

    这一步主要看AbstractRefreshableApplicationContext#refreshBeanFactory()中的loadBeanDefinitions()。

 1 protected final void refreshBeanFactory() throws BeansException {
 2     //如果BeanFactory不为空,则清除BeanFactory和里面的实例
 3     if (hasBeanFactory()) {
 4         destroyBeans();
 5         closeBeanFactory();
 6     }
 7     try {
 8         //BeanFactory 实例工厂
 9         DefaultListableBeanFactory beanFactory = createBeanFactory();
10         beanFactory.setSerializationId(getId());
11         //设置是否可以循环依赖 allowCircularReferences
12         //是否允许使用相同名称重新注册不同的bean实现.
13         customizeBeanFactory(beanFactory);
14         //解析xml,并把xml中的标签封装成BeanDefinition对象
15         loadBeanDefinitions(beanFactory);
16         this.beanFactory = beanFactory;
17     }
18     catch (IOException ex) {
19         throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
20     }
21 }

   3. prepareBeanFactory ***

   主要作用:设置BeanFactory的类加载器,添加一些默认的后置处理器,注册默认的系统环境bean:环境配置、系统属性、系统环境变量

   说明:上一步 obtainFreshBeanFactory 已经把工厂建好了,但是还不能投入使用,因为工厂里什么都没有,还需要配置一些东西

   4. postProcessBeanFactory ***

   主要作用:空方法 - 模版方法,由子类重写。让子类有机会在 BeanFactory 准备就绪后对其进行进一步的处理或配置:例如添加自定义的BeanPostProcessor、注册特定类型的Bean等。

   说明:这里采用模版方法设计模式,空方法,留给子类来实现

   5. invokeBeanFactoryPostProcessors ***

   主要作用:在应用上下文中调用所有注册的 BeanFactoryPostProcessor 实现类的 postProcessBeanFactory 方法,以便对 BeanFactory 进行进一步的定制和处理 

1 @FunctionalInterface
2 public interface BeanFactoryPostProcessor {
3     void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
4 
5 }

   说明:通常情况下,开发者可以通过实现 BeanFactoryPostProcessor 接口,在 postProcessBeanFactory 方法中编写自己的定制逻辑,以满足特定的需求。当调用 invokeBeanFactoryPostProcessors(beanFactory) 方法时,Spring 将自动扫描并调用所有注册的 BeanFactoryPostProcessor 实现类的 postProcessBeanFactory 方法,完成容器的预处理工作。

   6.  registerBeanPostProcessors ***

   主要作用:将自定义的配置文件中的BeanPostProcessor提取出来并注册进入beanFactory

   说明:这些后置处理器实现了 BeanPostProcessor 接口,用于在容器中的 Bean 创建、初始化、销毁等生命周期阶段进行特定操作。通过注册后置处理器,可以对容器中的 Bean 进行额外的处理,例如,AOP 切面的织入、自定义注解的处理、事件监听等。

   注册后置处理器是 Spring 框架实现灵活性和扩展性的重要手段之一,可以让开发者根据具体需求定制自己的处理逻辑,并将其无缝地集成到 Spring 容器中。

   7.  initMessageSource

   主要作用:初始化消息源,为 Spring 应用程序的国际化功能提供支持

   8.  initApplicationEventMulticaster

   主要作用:初始化事件管理类

   事件管理类用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 ApplicationContext 发布的 Event 广播给它的监听器列表。

   9.  onRefresh

   主要作用:模版方法,由子类重写。用于在容器刷新时执行特定的自定义操作:如创建Tomcat,Jetty等WEB服务器

   说明:在该方法中,可以添加任何希望在容器刷新完成后执行的逻辑,比如启动定时任务、初始化缓存、加载配置文件等等。通过重写这个方法,可以扩展容器刷新的行为,使得容器更适应特定的应用场景或业务需求。

   10.  registerListeners

   主要作用:注册监听器,将监听器注册到事件管理类中。

   11.  finishBeanFactoryInitialization *** 

   主要作用:实例化所有剩余的(非懒加载)的单例 Bean 

   如下图:

 

    

   此处只分析实际起作用的DefaultListableBeanFactory#preInstantiateSingletons() 方法。

   Spring在实例化的时候会进行判断,只有单例,并且不是LazyInit的Bean才会在初始化过程中创建,其他的比如Prototype或Lazy的只有在使用到时会通过getBean来创建。

   下面我们来分析实例化Bean的过程,DefaultListableBeanFactory#preInstantiateSingletons() :

 1 @Override
 2     public void preInstantiateSingletons() throws BeansException {
 3         // 先得到BeanDefinitionMap中已经注册的所有Bean Definition名称
 4         List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
 5         // 依次遍历所有的名称
 6         for (String beanName : beanNames) {
 7             // 获取bd(Bean Definition),判断当前bd所代表的类不是Abstract的,也不是需要延迟加载的并且是单例的。
 8             RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
 9             if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
10                 // 判断当前bd代表的类是否为工厂,此方法内部会调用依次getObject方法,由于Spring自己的类(BeanPostProcessor)在前面注册时已经实例化,故可以直接获取到。而自定义的Bean并不会生成对象,会通过bd来判断是否为工厂Bean,此处先不讨论FactoryBean的情况,先来分析普通Bean
11                 if (isFactoryBean(beanName)) {
12                     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
13                     if (bean instanceof FactoryBean) {
14                         final FactoryBean<?> factory = (FactoryBean<?>) bean;
15                         boolean isEagerInit;
16                         if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
17                             isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
18                                             ((SmartFactoryBean<?>) factory)::isEagerInit,
19                                     getAccessControlContext());
20                         }
21                         else {
22                             isEagerInit = (factory instanceof SmartFactoryBean &&
23                                     ((SmartFactoryBean<?>) factory).isEagerInit());
24                         }
25                         if (isEagerInit) {
26                             getBean(beanName);
27                         }
28                     }
29                 }
30                 else {
31                     // 这里从ioc容器中获取bean,如果不存在则创建
32                     getBean(beanName);
33                 }
34             }
35         }
36     }

    在preInstantiateSingletons方法里调用了AbstractBeanFactorygetBean方法。最终调用doGetBean()方法,下面我们看AbstractBeanFactory#doGetBean方法:

  1  protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
  2      //1.处理bean名称解析
  3      String beanName = this.transformedBeanName(name);
  4      Object sharedInstance = this.getSingleton(beanName);
  5      Object beanInstance;
  6      //从单例缓存中判断是否存在这个示例,可能来源于Spring启动的时候,也有可能来源于Spring 启动时初始化了非懒加载的对象
  7      if (sharedInstance != null && args == null) {
  8          if (this.logger.isTraceEnabled()) {
  9              if (this.isSingletonCurrentlyInCreation(beanName)) {
 10                  this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
 11              } else {
 12                  this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
 13              }
 14          }
 15          //如果单例工厂存在这个bean,则通过调用getObject方法获取bean实例
 16          beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
 17      } else {
 18          //如果当前线程存在这个实例,则抛出异常
 19          if (this.isPrototypeCurrentlyInCreation(beanName)) {
 20              throw new BeanCurrentlyInCreationException(beanName);
 21          }
 22          //2.获取当前bean工厂的父工厂,然后获取bean,此处是递归查找
 23          BeanFactory parentBeanFactory = this.getParentBeanFactory();
 24          if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
 25              String nameToLookup = this.originalBeanName(name);
 26              if (parentBeanFactory instanceof AbstractBeanFactory) {
 27                  
 28                  return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
 29              }
 30  
 31              if (args != null) {
 32                  //调用父工厂的getBean方法
 33                  return parentBeanFactory.getBean(nameToLookup, args);
 34              }
 35  
 36              if (requiredType != null) {
 37                  //根据类型获取bean
 38                  return parentBeanFactory.getBean(nameToLookup, requiredType);
 39              }
 40  
 41              return parentBeanFactory.getBean(nameToLookup);
 42          }
 43          //如果参数为检查类型,则设置名称为beanName的bean实例已经创建的标识
 44          if (!typeCheckOnly) {
 45              this.markBeanAsCreated(beanName);
 46          }
 47  
 48          StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);
 49  
 50          try {
 51              if (requiredType != null) {
 52                  beanCreation.tag("beanType", requiredType::toString);
 53              }
 54  
 55              RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
 56              this.checkMergedBeanDefinition(mbd, beanName, args);
 57              //3.获取bean的依赖属性
 58              String[] dependsOn = mbd.getDependsOn();
 59              String[] var12;
 60              if (dependsOn != null) {
 61                  var12 = dependsOn;
 62                  int var13 = dependsOn.length;
 63  
 64                  for(int var14 = 0; var14 < var13; ++var14) {
 65                      String dep = var12[var14];
 66                      //检查是否存在循环依赖
 67                      if (this.isDependent(beanName, dep)) {
 68                          throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 69                      }
 70                      //向注册器中注册这个依赖的bean
 71                      this.registerDependentBean(dep, beanName);
 72  
 73                      try {
 74                          //获取并解决当前bean
 75                          this.getBean(dep);
 76                      } catch (NoSuchBeanDefinitionException var31) {
 77                          throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31);
 78                      }
 79                  }
 80              }
 81              //根据 scope 处理当前bean
 82              if (mbd.isSingleton()) {
 83                  sharedInstance = this.getSingleton(beanName, () -> {
 84                      try {
 85                          return this.createBean(beanName, mbd, args);
 86                      } catch (BeansException var5) {
 87                          this.destroySingleton(beanName);
 88                          throw var5;
 89                      }
 90                  });
 91                  beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
 92              } else if (mbd.isPrototype()) {
 93                  var12 = null;
 94  
 95                  Object prototypeInstance;
 96                  try {
 97                      this.beforePrototypeCreation(beanName);
 98                      prototypeInstance = this.createBean(beanName, mbd, args);
 99                  } finally {
100                      this.afterPrototypeCreation(beanName);
101                  }
102  
103                  beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
104              } else {
105                  String scopeName = mbd.getScope();
106                  if (!StringUtils.hasLength(scopeName)) {
107                      throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
108                  }
109                  //5.类型转换
110                  Scope scope = (Scope)this.scopes.get(scopeName);
111                  if (scope == null) {
112                      throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
113                  }
114  
115                  try {
116                      Object scopedInstance = scope.get(beanName, () -> {
117                          this.beforePrototypeCreation(beanName);
118  
119                          Object var4;
120                          try {
121                              var4 = this.createBean(beanName, mbd, args);
122                          } finally {
123                              this.afterPrototypeCreation(beanName);
124                          }
125  
126                          return var4;
127                      });
128                      beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
129                  } catch (IllegalStateException var30) {
130                      throw new ScopeNotActiveException(beanName, scopeName, var30);
131                  }
132              }
133          } catch (BeansException var32) {
134              beanCreation.tag("exception", var32.getClass().toString());
135              beanCreation.tag("message", String.valueOf(var32.getMessage()));
136              //清除创建bean
137              this.cleanupAfterBeanCreationFailure(beanName);
138              throw var32;
139          } finally {
140              beanCreation.end();
141          }
142      }
143  
144      return this.adaptBeanInstance(name, beanInstance, requiredType);
145  }

    这里面涉及到解决Spring循环依赖的问题,详情请参考文章《Spring - 如何解决循环依赖》

    12.  finishRefresh

    主要作用:完成应用程序的上下文刷新,广播事件。其中包括:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,发布ContextRefreshedEvent事件。

    Eureka 注册会在 finishRefresh() 这个阶段。下面进行分析:

    入口是在finishRefresh方法中的this.getLifecycleProcessor().onRefresh();

    DefaultLifecycleProcessor#onRefresh

 

public void onRefresh() {
      // 负责启动和初始化这些已经创建的 Bean,包括执行生命周期中的初始化方法、事件监听器注册等操作。
      this.startBeans(true);

      // 确保容器已经完全启动并处于可运行状态
      this.running = true;
}

   Eureka 注册的时机选择在 finishRefresh() 中调用的 onRefresh() 方法,主要是因为:

   1)确保容器初始化完成

   Eureka 客户端是一个由 Spring 管理的 Bean,可能依赖于其他服务的配置或属性。只有在 Spring 上下文的初始化过程完成之后,所有的 Bean 才会被完全实例化和初始化。

   如果在这个之前注册,可能会导致服务注册时依赖的属性尚未被注入或初始化完成,从而导致注册失败或注册时信息不全

   2)Eureka 客户端的启动依赖

   在 Spring Cloud 中,Eureka 客户端通常是由 @EnableEurekaClient 或 @EnableDiscoveryClient 注解启动的,它会创建一个 EurekaClient 实例来与 Eureka 服务器通信并进行注册。EurekaClient 会在 Spring 容器启动之后连接到 Eureka 服务注册中心,并将当前应用注册到 Eureka 上。

   由于 EurekaClient 是一个 Spring Bean,它的创建和注册会被推迟到 Spring 容器的初始化完成后,确保容器内的依赖和配置都已准备好。

   3) 确保服务准备好注册

   容器的 running 状态确保服务已经处于可用状态,服务才可以进行注册并与注册中心正常通信。

   说明:无论是Dubbo 还是 Nacos,它们作为服务框架或服务注册中心,其服务注册的时机通常都在 Spring 上下文完全初始化之后,也就是在 finishRefresh() 阶段。

 二、refresh()方法中比较重要的类/接口进行梳理

    1. BeanFactory 接口

    BeanFactory 是IoC容器的基础接口。用于管理Bean的工厂,它负责创建、解析和管理Bean对象。在容器启动时,会先创建 BeanFactory,然后根据配置信息加载并初始化 Bean。

    2. BeanDefinition 接口

    Spring 实例化要通过 BeanDefinition。因为 Class 是无法完成 bean 的抽象,比如 bean 的作用域,bean 的注入模型,bean 是否是懒加载等等信息,Class是无法抽象出来的,故而需要一个 BeanDefinition 类来抽象这些信息。

    BeanDefinition类图如下:

   3.  BeanDefinitionRegistry 接口

   BeanDefinitionRegistry 是 Spring 框架中的一个接口,用于注册和管理 BeanDefinition,即用于定义和描述 Spring 中的 Bean。

   BeanDefinitionRegistry 接口定义了一系列方法,包括注册、移除、检索 BeanDefinition 等。通过这些方法,可以向 Spring 容器注册各种类型的 BeanDefinition,包括单例、原型、懒加载等,并指定它们的依赖关系、作用域、初始化方法、销毁方法等。

   通过使用 BeanDefinitionRegistry,开发人员可以动态地向 Spring 容器注册新的 BeanDefinition,从而实现灵活的 IoC(控制反转)和 DI(依赖注入)功能 

   结构如下:

   4. ConfigurableListableBeanFactory 接口

   它继承自 ListableBeanFactory 和 ConfigurableBeanFactory 接口,主要用于配置和管理 BeanFactory。

   总的来说,ConfigurableListableBeanFactory 提供了对 Spring IoC 容器的高级配置和管理功能,是 Spring 中 BeanFactory 的一个可配置的扩展接口。

   5.  DefaultListableBeanFactory 类

   它是Spring 框架中最常用的 IOC 容器实现之一,它支持 XML 配置和基于注解的配置,并提供了丰富的功能和灵活性,因此被广泛应用于各种类型的 Spring 应用中。

   它实现了 ConfigurableListableBeanFactory 和 BeanDefinitionRegistry 接口,提供了对 Bean 的定义和管理的基本功能。

   DefaultListableBeanFactory 是一个基本功能的 BeanFactory,它实现了 BeanDefinitionRegistry 接口。它的继承结构如下:

   DefaultListableBeanFactory 也是通过一个 HashMap 来管理 BeanDefinition 的,它比 SimpleBeanDefinitionRegistry多了一些其他的数据存储,使用上也更复杂。

   下面是其中一部分代码:

//用于保存BeanDefinition
/key:beanName value:BeanDefinition
private final Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

//已注册的beanName,按注册的顺序有序
private volatile List<string> beanDefinitionNames = new ArrayList<>(256);


//手动注册的singleton bean的名字,按注册的顺序有序
private volatile Set<string> manualsingletonNames = new LinkedHashSet<>(16);

   其中 registerBeanDefinition() 方法:

   负责管理 Spring IoC 容器中的 BeanDefinition,确保每个 Bean 都有一个唯一的名称,并处理覆盖和更新 BeanDefinition 的逻辑。

   6.  BeanFactoryPostProcessor 接口

   BeanFactoryPostProcessor 负责在 BeanFactory 加载 BeanDefinition 之后,但在 Bean 实例化之前,对 BeanFactory 进行处理。这样可以在容器启动过程中对 BeanFactory 进行修改,比如注册自定义的 BeanDefinition,修改属性值,添加属性转换器等。

   7. BeanPostProcessor 接口

   BeanPostProcessor类:

 1 public interface BeanPostProcessor {
 2 
 3     @Nullable
 4     default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 5         return bean;
 6     }
 7 
 8     @Nullable
 9     default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
10         return bean;
11     }
12 
13 }

   1)执行时机

   AbstractAutowireCapableBeanFactory#initializeBean

 1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 2     if (System.getSecurityManager() != null) {
 3         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 4             // 激活 Aware 方法
 5             invokeAwareMethods(beanName, bean);
 6             return null;
 7         }, getAccessControlContext());
 8     }
 9     else {
10         // 对特殊的 bean 处理:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware,使得 Bean 可以访问一些容器中特定的资源
11         invokeAwareMethods(beanName, bean);
12     }
13 
14     Object wrappedBean = bean;
15     if (mbd == null || !mbd.isSynthetic()) {
16         //执行BeanPostProcessor所有实现类的postProcessBeforeInitialization方法
17         wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
18     }
19 
20     try {
21         // 激活用户自定义的 init 方法
22         invokeInitMethods(beanName, wrappedBean, mbd);
23     }
24     catch (Throwable ex) {
25         throw new BeanCreationException(
26                 (mbd != null ? mbd.getResourceDescription() : null),
27                 beanName, "Invocation of init method failed", ex);
28     }
29     if (mbd == null || !mbd.isSynthetic()) {
30        //执行BeanPostProcessor所有实现类的postProcessAfterInitialization方法
31         wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
32     }
33     return wrappedBean;
34 }

   2)注册顺序

   在 Spring 中,注册后置处理器时会按照以下顺序进行排序:

  •    将实现了 PriorityOrdered 接口的后置处理器添加到 priorityOrderedPostProcessors 集合中,并按照 Ordered 接口或 @Order 注解的顺序进行排序。
  •    将实现了 Ordered 接口或使用 @Order 注解标注的后置处理器添加到 orderedPostProcessorNames 集合中。
  •    将未实现以上接口或注解的后置处理器添加到 nonOrderedPostProcessorNames 集合中。

   后置处理器的类型包括:

   实现了 BeanPostProcessor 接口的后置处理器,用于在 Bean 实例化、依赖注入和初始化阶段对 Bean 进行额外的处理。

   实现了 BeanFactoryPostProcessor 接口的后置处理器,用于在 BeanFactory 标准初始化后对 BeanFactory 进行额外的处理。

   实现了 MergedBeanDefinitionPostProcessor 接口的后置处理器,用于在 Bean 定义合并前后对 Bean 进行额外的处理。

   说明:MergedBeanDefinitionPostProcessor 接口是 BeanFactoryPostProcessor 的一个子接口,用于在 Bean 定义合并阶段进行操作,例如,可以通过这个后置处理器修改 Bean 的定义信息。

   8. ApplicationContext 接口

   ApplicationContext 实际上是 BeanFactory 的一个子接口,它扩展了 BeanFactory 的功能,提供了更多的企业级特性,比如国际化、事件发布、应用上下文的层级结构等。在 Spring 中,ApplicationContext 是 Spring IOC 容器的一种,而 BeanFactory 是 IOC 容器的基础接口。

   ApplicationContext 不直接暴露 BeanFactory 的所有功能,而是通过代理模式对其进行封装和增强,使其具有更多的功能。这种封装和增强的方式让 ApplicationContext 具有了更强大的特性,比如自动装配、AOP(面向切面编程)、事件处理等,从而更适合于企业级应用的开发。

   9. PostProcessorRegistrationDelegate 类

  是 Spring 框架中用于处理后置处理器(BeanPostProcessor)的注册工具类。其主要作用是负责管理后置处理器的注册和执行顺序

 

  参考链接:

  https://cloud.tencent.com/developer/article/2302663

  https://yangzhiwen911.github.io/zh/spring/

posted @ 2024-06-17 17:37  欢乐豆123  阅读(8)  评论(0编辑  收藏  举报