Spring Boot 源码分析(五)

125 阅读12分钟

应用上下文(接上)

刷新容器

refresh方法

实例化所有剩余的(非延迟初始化)单例

finishBeanFactoryInitialization(beanFactory);

该方法是整个 Spring Ioc 核心中的核心

该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。

finishBeanFactoryInitialization(beanFactory); 是 Spring 框架中的一个方法调用,它出现在 Spring 容器初始化过程中的某个阶段。在 Spring 的生命周期中,当 ApplicationContext 被创建和配置时,它负责初始化和管理应用程序中的 beans。

具体来说,finishBeanFactoryInitialization(beanFactory); 方法的主要目的是完成 bean 工厂的初始化,这包括:

  1. 实例化剩余的 singleton beans:在 Spring 的 ApplicationContext 中,beans 可以是原型(prototype)或单例(singleton)。在初始阶段,Spring 可能会预先实例化一些必要的 beans,但在调用 finishBeanFactoryInitialization 时,它会完成剩余的单例 beans 的实例化。
  2. 处理依赖关系:在这个阶段,Spring 会确保所有的 beans 都被正确创建,并且它们的依赖关系也被正确地注入。
  3. 触发生命周期回调:Spring 容器支持 bean 的生命周期回调,如 InitializingBean 接口的 afterPropertiesSet 方法或自定义的初始化方法。这些回调方法在这个阶段会被触发。

简而言之,finishBeanFactoryInitialization 方法是 Spring 容器初始化流程中的一个关键步骤,它确保所有的 beans 都已被创建、配置和初始化,并且它们的依赖关系也被正确处理。


内部实现

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // 初始化此上下文的转换服务
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }
   // 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析。
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }
   // 初始化LoadTimeWeaverAware Bean实例对象
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }
   beanFactory.setTempClassLoader(null);
   // 冻结所有bean定义,注册的bean定义不会被修改或进一步后处理,因为马上要创建 Bean 实例对象了
   beanFactory.freezeConfiguration();
   // 实例化所有剩余(非懒加载)单例对象
   beanFactory.preInstantiateSingletons();
}

接下来我们重点放在preInstantiateSingletons()方法上。

preInstantiateSingletons()实现

public void preInstantiateSingletons() throws BeansException {
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }
   // 1.创建beanDefinitionNames的副本beanNames用于后续的遍历,以允许init等方法注册新的bean定义
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
   // 2.遍历beanNames,触发所有非懒加载单例bean的初始化
   for (String beanName : beanNames) {
      // 3.获取beanName对应的MergedBeanDefinition
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 4.bd对应的Bean实例:不是抽象类 && 是单例 && 不是懒加载
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 5.判断beanName对应的bean是否为FactoryBean
         if (isFactoryBean(beanName)) {
            // 5.1 通过beanName获取FactoryBean实例
            // 通过getBean(&beanName)拿到的是FactoryBean本身;通过getBean(beanName)拿到的是FactoryBean创建的Bean实例
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               // 5.2 判断这个FactoryBean是否希望急切的初始化
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               // 5.3 如果希望急切的初始化,则通过beanName获取bean实例
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            // 6.如果beanName对应的bean不是FactoryBean,只是普通Bean,通过beanName获取bean实例
            getBean(beanName);
         }
      }
   }
   // 7.遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
   for (String beanName : beanNames) {
      // 7.1 拿到beanName对应的bean实例
      Object singletonInstance = getSingleton(beanName);
      // 7.2 判断singletonInstance是否实现了SmartInitializingSingleton接口
      if (singletonInstance instanceof SmartInitializingSingleton) {
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         // 7.3 触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}
关键代码解析:
getMergedLocalBeanDefinition(beanName)

MergedBeanDefinition:该词主要是用来表示 “合并的 bean 定义”,之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:

  • 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
  • 该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
  • 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。

源码解释:

protected RootBeanDefinition getMergedBeanDefinition(
      String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
      throws BeanDefinitionStoreException {
   // 1.加锁再进行操作
   synchronized (this.mergedBeanDefinitions) {
      // 用于存储bd的MergedBeanDefinition,也就是该方法的结果
      RootBeanDefinition mbd = null;
      RootBeanDefinition previous = null;
      if (containingBd == null) {
         // 2.检查beanName对应的MergedBeanDefinition是否存在于缓存中
         mbd = this.mergedBeanDefinitions.get(beanName);
      }
      // 3.如果beanName对应的MergedBeanDefinition不存在于缓存中
      if (mbd == null || mbd.stale) {
         previous = mbd;
         if (bd.getParentName() == null) {
            // 4.如果bd的parentName为空,代表bd没有父定义,无需与父定义进行合并操作,
            // 也就是bd的MergedBeanDefinition就是bd本身(可能需要转成RootBeanDefinition)
            if (bd instanceof RootBeanDefinition) {
               // 4.1 如果bd的类型为RootBeanDefinition,则bd的MergedBeanDefinition就是bd本身,则直接克隆一个副本
               mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
            }
            else {
               // 4.2 否则,将bd作为参数,构建一个RootBeanDefinition。
               // 正常使用下,BeanDefinition在被加载后是GenericBeanDefinition或ScannedGenericBeanDefinition
               // 使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;如果使用注解的方式来注册 bean,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。
               mbd = new RootBeanDefinition(bd);
            }
         }
         else {
            // 5.否则,bd存在父定义,需要与父定义合并
            BeanDefinition pbd;
            try {
               // 5.1 获取父定义的beanName
               String parentBeanName = transformedBeanName(bd.getParentName());
               // 5.2 如果父定义的beanName与该bean的beanName不同
               if (!beanName.equals(parentBeanName)) {
                  // 5.3 获取父定义的MergedBeanDefinition(因为父定义也可能有父定义,也就是bd的爷爷定义...)
                  pbd = getMergedBeanDefinition(parentBeanName);
               }
               else {
                  // 5.4 如果父定义的beanName与bd的beanName相同,则拿到父BeanFactory,
                  // 只有在存在父BeanFactory的情况下,才允许父定义beanName与自己相同,否则就是将自己设置为父定义
                  BeanFactory parent = getParentBeanFactory();
                  if (parent instanceof ConfigurableBeanFactory) {
                     // 5.5 如果父BeanFactory是ConfigurableBeanFactory,则通过父BeanFactory获取父定义的MergedBeanDefinition
                     pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                  }
                  else {
                     // 5.6 如果父BeanFactory不是ConfigurableBeanFactory,则抛异常
                     throw new NoSuchBeanDefinitionException(parentBeanName,
                           "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                           "': cannot be resolved without a ConfigurableBeanFactory parent");
                  }
               }
            }
            catch (NoSuchBeanDefinitionException ex) {
               throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                     "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
            }
            // 5.7 使用父定义pbd构建一个新的RootBeanDefinition对象(深拷贝)
            mbd = new RootBeanDefinition(pbd);
            // 5.8 使用bd覆盖父定义
            mbd.overrideFrom(bd);
         }
         // 6.如果没有配置scope,则设置成默认的singleton
         if (!StringUtils.hasLength(mbd.getScope())) {
            mbd.setScope(SCOPE_SINGLETON);
         }
         // 7.如果containingBd不为空 && containingBd不为singleton && mbd为singleton,则将mdb的scope设置为containingBd的scope
         if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
            mbd.setScope(containingBd.getScope());
         }
         // 8.将beanName与mbd放到mergedBeanDefinitions缓存,以便之后可以直接使用
         if (containingBd == null && isCacheBeanMetadata()) {
            this.mergedBeanDefinitions.put(beanName, mbd);
         }
      }
      if (previous != null) {
         copyRelevantMergedBeanDefinitionCaches(previous, mbd);
      }
      // 9.返回MergedBeanDefinition
      return mbd;
   }
}

其中5.1:transformedBeanName内部实现如下:

protected String transformedBeanName(String name) {
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
   Assert.notNull(name, "'name' must not be null");
   if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
      return name;
   }
   // 如果beanName带有 "&" 前缀,则去掉
   return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
      do {
         beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
      }
      while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
      return beanName;
   });
}
public String canonicalName(String name) {
   String canonicalName = name;
   String resolvedName;
   do {
      // 将别名解析成真正的beanName
      resolvedName = this.aliasMap.get(canonicalName);
      if (resolvedName != null) {
         canonicalName = resolvedName;
      }
   }
   while (resolvedName != null);
   return canonicalName;
}

为了区分 “FactoryBean” 和 “FactoryBean 创建的 bean 实例”,Spring 使用了 “&” 前缀。假设我们的 beanName 为 name,则 getBean("name") 获得的是自定义FactoryBean通过 getObject() 方法创建的 bean 实例;而 getBean("&name") 获得的是自定义FactoryBean本身。

例子如下:

public class NameFactoryBean implements FactoryBean<Name> {
    @Override
    public Name getObject() throws Exception {
        Name name = new Name();
        apple.setName("name");
        return name;
    }
    @Override
    public Class<?> getObjectType() {
        return Name.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}

其中5.3:getMergedBeanDefinition内部实现如下:

public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
   // 1.获取真正的beanName(解析别名)
   String beanName = transformedBeanName(name);
   // 2.如果当前BeanFactory中不存在beanName的Bean定义 && 父beanFactory是ConfigurableBeanFactory,
   // 则调用父BeanFactory去获取beanName的MergedBeanDefinition
   if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
      return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
   }
   // 3.在当前BeanFactory中解析beanName的MergedBeanDefinition
   return getMergedLocalBeanDefinition(beanName);
}

父 BeanFactory

在 Spring 中可能存在多个 BeanFactory,多个 BeanFactory 可能存在 “父工厂” 与 “子工厂” 的关系。最常见的例子就是:Spring MVC 的 BeanFactory 和 Spring 的 BeanFactory,通常情况下,Spring 的 BeanFactory 是 “父工厂”,Spring MVC 的 BeanFactory 是 “子工厂”,在 Spring 中,子工厂可以使用父工厂的 BeanDefinition,因而,如果在当前 BeanFactory 中找不到,而又存在父工厂,则会去父工厂中查找。

isFactoryBean(beanName)
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
   // 1.拿到真正的beanName(去掉&前缀、解析别名)
   String beanName = transformedBeanName(name);
   // 2.尝试从缓存获取Bean实例对象
   Object beanInstance = getSingleton(beanName, false);
   if (beanInstance != null) {
      // 3.beanInstance存在,则直接判断类型是否为FactoryBean
      return (beanInstance instanceof FactoryBean);
   }
   // 4.如果beanInstance为null,并且beanName在单例对象缓存中,则代表beanName对应的单例对象为空对象,返回false
   if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
      // 5.如果缓存中不存在此beanName && 父beanFactory是ConfigurableBeanFactory,则调用父BeanFactory判断是否为FactoryBean
      return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
   }
   // 6.通过MergedBeanDefinition来检查beanName对应的Bean是否为FactoryBean
   return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}

其中2:getSingleton内部实现如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 1.从单例对象缓存中获取beanName对应的单例对象
   Object singletonObject = this.singletonObjects.get(beanName);
   // 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         // 3.加锁进行操作
         synchronized (this.singletonObjects) {
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               // 4.从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
            // 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
               singletonObject = this.earlySingletonObjects.get(beanName);
               // 5.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
               if (singletonObject == null) {
                  // 6.从单例工厂缓存中获取beanName的单例工厂
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     // 7.如果存在单例对象工厂,则通过工厂创建一个单例对象
                     singletonObject = singletonFactory.getObject();
                     // 8.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     // 9.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了,
                    // 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   // 10.返回单例对象
   return singletonObject;
}

该段代码是 Spring 解决循环依赖的核心代码

循环依赖

image.png

由上可知,循环依赖其实就是一个闭环,像图中情况二Spring在创建单例bean A的时候发现引用了B,这时候就会去容器中查找单例bean B,发现没有然后就会创建bean B,创建bean B时又发现引用了bean A,这时候又会去容器中查找bean A,发现没有,接下来就会循环重复上面的步骤,循环依赖就是一个死循环的过程。

首先需要强调一点,虽然Spring允许Bean对象的循环依赖,但事实上,项目中存在Bean的循环依赖,是Bean对象职责划分不明确、代码质量不高的表现,如果存在大量的Bean之间循环依赖,那么代码的整体设计也就越来越糟糕。所以SpringBoot在后续的版本中终于受不了这种滥用,默认把循环依赖给禁用了!从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!

***************************
APPLICATION FAILED TO START
***************************
​
Description:
​
The dependencies of some of the beans in the application context form a cycle:
​
┌─────┐
|  UserService (field private com.plasticene.fast.service.impl.RoleService com.plasticene.fast.service.impl.UserService.roleService)
↑     ↓
|  RoleService (field private com.plasticene.fast.service.impl.UserService com.plasticene.fast.service.impl.RoleService.userService)
└─────┘

接下来我们在配置文件中配置开启允许循环依赖

spring:
  main:
    allow-circular-references: true

项目就能正常启动了。

但对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖。

解决方案

Spring解决循环依赖的核心思想在于提前曝光,使用三级缓存进行提前曝光。

DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map作为三级缓存:

public class DefaultSingletonBeanRegistry ... {
  //1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
  Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
  //2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
  Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
  //3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
  Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

步骤如下:

  1. 通过构建函数创建A对象(A对象是半成品,还没注入属性和调用init方法)。
  2. A对象需要注入B对象,发现缓存里还没有B对象,将半成品对象A放入半成品缓存
  3. 通过构建函数创建B对象(B对象是半成品,还没注入属性和调用init方法)。
  4. B对象需要注入A对象,从半成品缓存里取到半成品对象A
  5. B对象继续注入其他属性和初始化,之后将完成品B对象放入完成品缓存
  6. A对象继续注入属性,从完成品缓存中取到完成品B对象并注入。
  7. A对象继续注入其他属性和初始化,之后将完成品A对象放入完成品缓存

小问:解决循环依赖只需要一个半成品缓存即可,为何还需要三级缓存(singletonFactories)?

答:第三级缓存(singletonFactories)是为了处理 Spring 的 AOP的。

  • 三级缓存利用 ObjectFactorygetEarlyBeanReference() 提前执行 AOP 操作生成代理对象。

  • 在上移到二级缓存时,如果 Bean 中有 AOP 操作,那么提前暴露的对象会是 AOP 操作后返回的代理对象;如果没有 AOP 操作,那么提前暴露的对象会是原始对象。

  • 当出现循环依赖问题时,注入依赖的对象和最终生成的对象会是同一个对象。