admin管理员组

文章数量:1531792

前言

内容主要参考自《Spring源码深度解析》一书,算是读书笔记或是原书的补充。进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情。

本文主要涉及书中第五章的部分,依照书中内容以及个人理解对Spring进行了注释,详见Github仓库:https://github/MrSorrow/spring-framework

在前几篇文章中,我们已经完成了将XML配置文件的信息转换为 BeanDefinition 的形式,将所有的 bean 从配置文件加载到内存中,接下来便是如何来 使用加载 这些 beanbean 加载的功能实现远比 bean 的解析要复杂的多。

I. 加载bean总览

我们在 spring-mytest 模块中,获取实例对象通过如下代码:

MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");

Spring通过调用 BeanFactorygetBean() 方法来加载 bean,我们进入 AbstractBeanFactory 来看一下源码:

/**
 * 根据名称获取bean实例
 * @param name the name of the bean to retrieve
 * @return
 * @throws BeansException
 */
@Override
public Object getBean(String name) throws BeansException {
   
    return doGetBean(name, null, null, false);
}

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   

    // 提取对应的bean名称
    final String beanName = transformedBeanName(name);
    Object bean;

    // 检查缓存中或者实例工厂中是否有对应的实例
    // 为什么会首先使用这段代码?
    // 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
    // Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
    // 也就是将ObjectFactory加入到缓存中,一旦下个bean创建的时候需要依赖上个bean则直接使用ObjectFactory

    // 直接尝试从缓存中获取或者singletonFactories中的ObjectFactory中获取
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
   
        if (logger.isDebugEnabled()) {
   
            if (isSingletonCurrentlyInCreation(beanName)) {
   
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                             "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
   
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。有时候存在诸如BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    // 缓存中取不到
    else {
   
        // 只有在单例情况下才会尝试解决循环依赖;
        // 原型模式情况下,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为
        // 对于B的创建再次返回到创建A,造成循环依赖,也就是下面的情况。对于“prototype”作用域Bean,Spring容器无法完成依赖注入,
        // 因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
        // 参考:http://wwwblogs/bhlsheji/p/5208076.html
        // isPrototypeCurrentlyInCreation(beanName)为true
        if (isPrototypeCurrentlyInCreation(beanName)) {
   
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        BeanFactory parentBeanFactory = getParentBeanFactory();

        // 如果beanDefinitionMap中也就是已经加载的类中不包括beanName则尝试从parentBeanFactory中检测
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
   
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
   
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
   
                // Delegation to parent with explicit args.
                // 递归到BeanFactory中寻找
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
   
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        // 如果不仅仅是做类型检查则是创建bean,这里要进行记录
        if (!typeCheckOnly) {
   
            markBeanAsCreated(beanName);
        }

        try {
   
            // 将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话同时会合并父类的相关属性
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            String[] dependsOn = mbd.getDependsOn();
            // 若存在依赖则需要递归实例化依赖的bean
            if (dependsOn != null) {
   
                for (String dep : dependsOn) {
   
                    if (isDependent(beanName, dep)) {
   
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 缓存依赖调用
                    registerDependentBean(dep, beanName);
                    try {
   
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
   
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            // 实例化依赖的bean后便可以实例化mbd本身了
            // singleton模式的创建
            if (mbd.isSingleton()) {
   
                sharedInstance = getSingleton(beanName, () -> {
   
                    try {
   
                        // 核心所在
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
   
                        // Explicitly remove instance from singleton cache: It might have been put there
                        // eagerly by the creation process, to allow for circular reference resolution.
                        // Also remove any beans that received a temporary reference to the bean.
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
   
                // It's a prototype -> create a new instance.
                // prototype原型模式的创建(new)
                Object prototypeInstance = null;
                try {
   
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
   
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
   
                // 指定的scope上实例化bean
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
   
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
   
                    Object scopedInstance = scope.get(beanName, () -> {
   
                        beforePrototypeCreation(beanName);
                        try {
   
                            return createBean(beanName, mbd, args);
                        }
                        finally {
   
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
   
                    throw new BeanCreationException(beanName,
                                                    "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                                    "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                                    ex);
                }
            }
        }
        catch (BeansException ex) {
   
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

这段代码可以说是巨长了,其中的过程相当复杂,同时可以根据本文的长度可见一斑。通过上面的注释,大致了解到Spring加载 bean 的过程如下:

① 转换对应的beanName

转换对应的 beanName 是根据 getBean(String name) 方法传入的 name 参数进行的,传入的 name 并不一定是 beanName,可能是别名,也可能是 FactoryBean 。至于什么是 FactoryBean ,后面会提及。由于 name 的多种可能,Spring会进行对应的转换。

  • 去除 FactoryBean 的修饰符,一般就是去除 name 参数的 & 前缀,从代码上能够清晰的看出;
  • 取指定的 alias 所表示的最终 beanName,例如别名 A 指向别名 B,别名 B 指向名称为 Cbean,则最后返回 C
/**
 * Return the bean name, stripping out the factory dereference prefix if necessary,
 * and resolving aliases to canonical names.
 * @param name the user-specified name
 * @return the transformed bean name
 */
protected String transformedBeanName(String name) {
   
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

去除 FactoryBean 的修饰符:

/**
 * 去掉xml中bean标签name属性的前缀&
 * Return the actual bean name, stripping out the factory dereference
 * prefix (if any, also stripping repeated factory prefixes if found).
 * @param name the name of the bean
 * @return the transformed name
 * @see BeanFactory#FACTORY_BEAN_PREFIX
 */
public static String transformedBeanName(String name) {
   
   Assert.notNull(name, "'name' must not be null");
   String beanName = name;
   while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
   
      beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
   }
   return beanName;
}

取指定的 alias 所表示的最终 beanName

/**
 * Determine the raw name, resolving aliases to canonical names.
 * @param name the user-specified name
 * @return the transformed name
 */
public String canonicalName(String name) {
   
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
   
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
   
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

② 尝试从缓存中加载单例

单例在Spring中的同一个容器内只会被创建一次,后续再获取 bean,则直接从单例缓存中获取了。当然代码实现上首先进行尝试从缓存中进行加载,如果不成功再尝试从 singletonFactories 中加载,最后都不行才判断是没有创建过所以新建并放入缓存。之所以需要从 singletonFactories 中加载,因为在创建单例 bean 的时候会存在依赖注入 的情况,而在创建依赖 bean 的时候,为了避免循环依赖,Spring中创建 bean 的原则是不等 bean 创建完成就会提前将创建 beanObjectFactory 曝光加入到缓存中,一旦下一个 bean 创建的时候需要依赖该 bean 时则可以直接使用 ObjectFactory 作为依赖进行注入。对于循环依赖,后面会具体再说。

③ bean的实例化

如果从缓存中得到了 bean 的原始状态,则需要对 bean 进行实例化。缓存中记录的只是最原始的 bean 状态,并不是我们最终想要的 bean。例如:假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance(sharedInstance, name, beanName, null) 就是完成这项工作。对于原始状态的 bean 进行实例化,后面也会具体说。

④ 原型模式(prototype)的依赖检查

Spring能够尝试解决的循环依赖问题只有单例模式下,对于原型模式的循环依赖问题Spring是没有方法解决的。因为在原型模式(prototype)下,如果 A 依赖 BB 同时又依赖 A,那么就会出现创建 A 时因为创建依赖 B 而又要创建 A ,因为是多例的,所以会一直循环创建。Spring对于原型模式下的循环依赖会进行检测,检测代码为 isPrototypeCurrentlyInCreation(beanName) ,如果为 true,则会抛出异常。

if (isPrototypeCurrentlyInCreation(beanName)) {
   
    throw new BeanCurrentlyInCreationException(beanName);
}

⑤ 检测parentBeanFactory

代码上的逻辑可以看出,如果从缓存中没有取到,那么直接转到父类工厂上去加载了。Why?代码中的判断逻辑是:if (parentBeanFactory != null && !containsBeanDefinition(beanName)) ,前半部分还好,parentBeanFactory 不能为空,后半部分 !containsBeanDefinition(beanName) 意思如果当前的 beanDefinitionMap (XML配置文件)中没有 beanName 对应的配置,就只能到 parentBeanFactory 中去尝试下,再递归的调用 getBean() 方法了。

// 如果beanDefinitionMap中也就是已经加载的类中不包括beanName则尝试从parentBeanFactory中检测
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
   
   // Not found -> check parent.
   String nameToLookup = originalBeanName(name);
   if (parentBeanFactory instanceof AbstractBeanFactory) {
   
      return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
            nameToLookup, requiredType, args, typeCheckOnly);
   }
   else if (args != null) {
   
      // Delegation to parent with explicit args.
      // 递归到BeanFactory中寻找
      return (T) parentBeanFactory.getBean(nameToLookup, args);
   }
   else {
   
      // No args -> delegate to standard getBean method.
      return parentBeanFactory.getBean(nameToLookup, requiredType);
   }
}

⑥ GenericBeanDefinition转为RootBeanDefinition

如果从缓存中获取不到,同时当前的 beanDefinitionMap 中存在对应 beanName 的配置,我们就可以依据包含有XML配置文件信息的 beanDefinition 进行创建 bean 了。通过前面几篇文章,我们知道从XML配置文件中读取到的 bean 信息是利用 GenericBeanDefinition 存储的,但是后面Spring对所有 bean 的后续处理都是针对于 RootBeanDefinition 的,所以需要进行转换,转换的同时如果父类 bean 不为空,则会一并合并父类的属性

// 将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话同时会合并父类的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

⑦ 寻找依赖

因为 bean 的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置的成依赖于其他的 bean,那么此时应该先加载依赖的 bean。所以在流程中,Spring初始化一个 bean,会先初始化其依赖的所有的其他 bean

// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
// 若存在依赖则需要递归实例化依赖的bean
if (dependsOn != null) {
   
   for (String dep : dependsOn) {
   
      if (isDependent(beanName, dep)) {
   
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
      }
      // 缓存依赖调用
      registerDependentBean(dep, beanName);
      try {
   
         getBean(dep);
      }
      catch (NoSuchBeanDefinitionException ex) {
   
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
      }
   }
}

⑧ 依据scope创建bean

Spring存在不同的 scope,其中默认的是 singleton,但是还有其他的配置像 prototyperequest 等。(关于Spring的几种 scope 介绍,参考这篇文章。)在这一步中,Spring会根据配置进行采取对应的初始化策略。代码缩略如下:

if (mbd.isSingleton()) {
   
   .....
}

else if (mbd.isPrototype()) {
   
   // It's a prototype -> create a new instance.
   // prototype原型模式的创建(new)
   .....
}

else {
   
   // 指定的scope上实例化bean
   .....
}

⑨ 类型转换

根据 scope 创建完 bean 成功后,一般可以直接返回即可。但当传入 doGetBean 方法中的 requireType 参数不为空时,意味着我们对最后返回的 bean 有着类型上的要求。Spring一般通过类型转换器将第⑧步创建完成的 bean 转换为 requireType 指定的类型。Spring自身提供了一些转换器,用户也可以自己扩展转换器来满足需求。

// 检查需要的类型是否符合bean的实际类型
if (requiredType != null && !requiredType.isInstance(bean)) {
   
   try {
   
      T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
      if (convertedBean == null) {
   
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
      return convertedBean;
   }
   catch (TypeMismatchException ex) {
   
      if (logger.isDebugEnabled()) {
   
         logger.debug("Failed to convert bean '" + name + "' to required type '" +
               ClassUtils.getQualifiedName(requiredType) + "'", ex);
      }
      throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
   }
}
return (T) bean;

经过以上的九个步骤,bean 就算创建完成了,整个流程如下图所示。其中第八步最为关键——针对不同的 scope 进行 bean 的创建。

)

这里再附一张其他文章中的流程图:

在真正开始分析流程前,我们先来做些知识准备工作…

II. FactoryBean的使用

一般情况下,Spring通过反射机制来实例化 bean。在某些情况下,实例化一个 bean 的过程较为复杂,因此配置文件中为该 bean 需要编写大量配置信息,灵活性受限。所以,Spring提供了一个 org.springframework.beans.factory.FactoryBean 的工厂类接口,用户可以实现该接口通过编码的方式定制实例化 bean 的逻辑。简单点,就是配置文件配置自定义的 FactoryBean 接口实现类,但真正实例化出的还是我们需要的对象,只不过繁琐的实例化流程交给 FactoryBean 和Spring商量了。

FactoryBean接口

Spring自身就定义了 70 多种 FactoryBean 的实现,他们隐藏了实例化一些复杂 bean 的细节,给上层应用带来便利。 FactoryBean 接口的定义从 3.0 开始支持泛型:

public interface FactoryBean<T> {
   
   @Nullable
   T getObject() throws Exception;

   @Nullable
   Class<?> getObjectType();

   default boolean isSingleton() {
   
      return true;
   }
}

接口中定义了三个方法:

  • T getObject(): 返回由 FactoryBean 创建的 bean 实例。如果 isSingleton() 返回 true,则该实例会放到Spring容器中单例缓存池中;
  • boolean isSingleton(): 返回 bean 的作用域是否是单例模式,默认为 true
  • Class<?> getObjectType(): 返回 FactoryBean 创建的 bean 的类型。

使用示例

当XML配置文件中 <bean>class 属性配置的实现类是 FactoryBean 接口实现类时,通过 T getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBeanT getObject() 方法返回的对象。

例如,我们定义一个 Car 实体类,需要在Spring中创建 bean,那么需要指定一些 <property> 配置才行。

/**
 * @description: 汽车实体类
 * @author: guoping wang
 * @date: 2018/9/5 10:43
 * @project: spring
 */
public class Car {
   

   private int maxSpeed;
   private String brand;
   private double price;

   /** setter and getter */
}

使用 FactoryBean 的方式就可以灵活许多,但我们需要自定义 FactoryBean 的实现类:

import org.springframework.beans.factory.FactoryBean;

/**
 * @description: 实现FactoryBean接口创建Car对象
 */
public class CarFactoryBean implements FactoryBean<Car> {
   

   private String carInfo;

   public String getCarInfo() {
   
      return carInfo;
   }

   public void setCarInfo(String carInfo) {
   
      this.carInfo = carInfo;
   }

   @Override
   public Car getObject() throws Exception {
   
      Car car = new Car();
      String[] splitInfo = carInfo.split(",");
      car.setBrand(splitInfo[0]);
      car.setMaxSpeed(Integer.valueOf(splitInfo[1]));
      car.setPrice(Double.valueOf(splitInfo[2]));
      return car;
   }

   @Override
   public Class<Car> getObjectType() {
   
      return Car.class;
   }

   @Override
   public boolean isSingleton() {
   
      return false;
   }
}

最重要的其实就是 T getObject() 方法的重写,其中包含着 Car 实例对象的创建逻辑、属性如何填充等。有了 CarFactoryBean ,在配置文件中我们可以很简洁的定义。

<bean id="testCarFactoryBean" class="guo.ping.ioc.loadbean.CarFactoryBean">
   <property name="carInfo" value="超跑,400,200000" />
</bean>

当Spring通过反射发现 guo.ping.ioc.loadbean.CarFactoryBean 实现了 FactoryBean 接口时,Spring容器会自动调用 CarFactoryBeanCar getObject() 方法返回一个 Car 实例对象。当然,如果你本身只想返回 CarFactoryBean 的实例,那么在使用 getBean(beanName) 方法时在 beanName 前显式的加上 “&” 前缀,例如 getBean("&car")

CarFactoryBean carFactoryBean = (CarFactoryBean) beanFactory.getBean("&testCarFactoryBean");

III. 缓存中获取单例bean

下面我们就正式的开始分析 bean 加载的九大步骤。第一步没什么太多需要再说的了,就是对 name 参数的处理,转换对应的 beanName。相信通过第二部分 FactoryBean 的介绍,更应该了解到去除 FactoryBean 的修饰符含义了。

单例在Spring的同一个容器内只会被创建一次,后续再获取 bean 直接从单例缓存中获取。当然这里也只是尝试加载,首先尝试从 缓存 中加载,然后再次尝试从 singletonFactory 加载。因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建 bean 的原则是不等 bean 创建完成就会将创建 beanObjectFactory 提早曝光加入到缓存中,一旦下一个 bean 创建时需要依赖上个 bean,则直接使用ObjectFactory 。我们进入 getSingleton(beanName) 方法体中研究一下:

/**
 * 尝试从缓存中加载bean,然后再尝试从singletonFactories中加载
 * @param beanName the name of the bean to look for
 * @return
 */
@Override
@Nullable
public Object getSingleton(String beanName) {
   
   // 参数true设置标识允许早期依赖
   return getSingleton(beanName, true);
}

/**
 * 首先尝试从缓存singletonObjects获取实例,如果获取不到再从earlySingletonObjects获取
 * 如果还是获取不到,再从singletonFactories中获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject方法
 * 来创建bean,并放到earlySingletonObjects,并从singletonFactories移除掉这个ObjectFactory
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   
   // 检查缓存中是否存在实例
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   
      // 如果缓存中不存在,则锁定全局变量并进行处理
      synchronized (this.singletonObjects) {
   
         // 如果此bean正在加载则不处理
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
   
            // 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
   
               // 如果singletonFactory中存在,调用预先设定的getObject方法
               singletonObject = singletonFactory.getObject();
               // 记录在缓存中,earlySingletonObjects和singletonFactories互斥
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

根据注释,我们梳理一下获取缓存 bean 代码的主要逻辑。方法先尝试从 singletonObjects 里面去获取实例,如果获取到,OK,直接返回!如果获取不到,再尝试从 earlySingletonObjects 里面获取,如果获取到,OK,直接返回。那么如果还获取不到,再尝试从 singletonFactories 里面获取 beanName 对应的 ObjectFactory。然后再调用这个 ObjectFactorygetObject() 方法创建 bean,并放到 earlySingletonObjects 里面去,并且从 singletonFactories 里面 remove 掉这个 ObjectFactory,而对于后续所有的内存操作都只为了循环依赖检测时候使用,即 allowEarlyReferencetrue 的时候才会使用。关于循环依赖、 ObjectFactory 后面还会单独着重介绍。

在从缓存中获取未果转向从 earlySingletonObjects 里面获取时,还要判断单例对象是否正在被创建 isSingletonCurrentlyInCreation(beanName) 。只有该 bean 正在被创建 earlySingletonObjectssingletonFactories 里面才可能有。

/**
 * Return whether the specified singleton bean is currently in creation
 * (within the entire factory).
 * @param beanName the name of the bean
 */
public boolean isSingletonCurrentlyInCreation(String beanName) {
   
   return this.singletonsCurrentlyInCreation.contains(beanName);
}

代码中涉及到很多个存储 bean 的不同 map 集合。我们来罗列一下:

/** 用于保存BeanName和创建bean实例之间的关系
Cache of singleton objects: bean name to bean instance.
 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 用于保存BeanName和创建bean的工厂之间的关系 
Cache of singleton factories: bean name to ObjectFactory.
 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** 也是保存BeanName和创建bean实例之间的关系,与singletonObjects不同之处在于,当一个单例bean被放在里面后,
 * 那么bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来循环检测引用
 * Cache of early singleton objects: bean name to bean instance.
 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** 用来保存当前所有已注册的bean 
Set of registered singletons, containing the bean names in registration order.
 */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256); 

IV. 从工厂bean的实例中获取对象

在整个 getBean() 方法中,getObjectForBeanInstance(sharedInstance, name, beanName, null) 是一个高频率使用的方法。从上一步的缓存中获取了单例 bean 以及根据不同的 scope 策略加载 bean 都使用了该方法。总之,我们得到 bean 的实例后,要做的第一步就是调用这个方法来检测一下正确性,其实就是检测获得 bean 是不是 FactoryBean 类型的 bean。如果是,那么需要调用该 bean 对应的 FactoryBean 实例中的 getObject() 作为返回值。

无论是从缓存中获取到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但我们真正想要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而getObjectForBeanInstance 方法就是完成这个。

/**
 * 如果从缓存中获取到的bean还是通过不同的scope策略加载到的bean都只是最原始的bean状态
 * 并不一定是我们最终想要的bean。
 * 比如,假如我们需要对工厂bean进行处理,那么之前得到的其实是工厂bean的初始状态,但我们真正需要的是
 * 工厂bean中定义的factory-method方法返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。
 */
protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
   

   // 如果指定的name是工厂相关(是否以&为前缀)
   if (BeanFactoryUtils.isFactoryDereference(name)) {
   
      // 如果beanInstance是null,则直接返回
      if (beanInstance instanceof NullBean) {
   
         return beanInstance;
      }
      // 如果指定的name是工厂相关且beanInstance不是FactoryBean类型,则验证不通过
      if (!(beanInstance instanceof FactoryBean)) {
   
         throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
      }
   }

   // 现在我们有了bean的实例,这个实例可能会是正常的bean或者factoryBean
   // 如果是FactoryBean我们使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的name应该加入&
   if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) 	 {
   
      return beanInstance;
   }

   // 加载FactoryBean
   Object object = null;
   if (mbd == null) {
   
      // 尝试从缓存中加载bean,如果缓存中已经存在 beanName 对应的工厂 bean 生成的对象则直接返回
      object = getCachedObjectForFactoryBean(beanName);
   }
   if (object == null) {
   
      // 到这里已经明确知道beanInstance一定是FactoryBean类型
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // containsBeanDefinition检测beanDefinitionMap中也就是在所有已经加载的类中检测是否定义beanName
      if (mbd == null && containsBeanDefinition(beanName)) {
   
         // 将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话同时会合并父类的相关属性
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      // 是否是用户定义的而不是应用程序本身定义的
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      // getObjectFromFactoryBean是本方法的核心
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}

我们详细分析下代码会发现此方法中没有重要信息,大多都是一些辅助功能性的检查判断,而真正的核心功能是在 getObjectFromFactoryBean(factory, beanName, !synthetic) 方法中实现的。不过可以看出,之前第二部分的 FactoryBean 使用相关功能的处理逻辑就是在这里实现的。总的来说,getObjectForBeanInstance 中做了如下几件事情:

  • beanInstance 进行 FactoryBean 正确性的校验;
  • 对非 FactoryBean 类型或者本身就需要返回 FactoryBean 类型对象的 beanInstance 不作处理;
  • 如果缓存中已经存在 beanName 对应的工厂 bean 生成的对象则直接返回;
  • 如果缓存没有,则对 beanInstance 进行强转为 FactoryBean 类型,将从 Factory 中解析获取 bean 的工作委托给 getObjectFromFactoryBean(factory, beanName, !synthetic) 方法。

其中,在直接创建之前会尝试获取缓存,通过 getCachedObjectForFactoryBean(beanName) 方法获取:

/**
 * Obtain an object to expose from the given FactoryBean, if available
 * in cached form. Quick check for minimal synchronization.
 * @param beanName the name of the bean
 * @return the object obtained from the FactoryBean,
 * or {@code null} if not available
 */
@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
   
   return this.factoryBeanObjectCache.get(beanName);
}

我们继续查看 getObjectFromFactoryBean(factory, beanName, !synthetic)

/**
 * 从FactoryBean获取对象
 * Obtain an object to expose from the given FactoryBean.
 * @param factory the FactoryBean instance
 * @param beanName the name of the bean
 * @param shouldPostProcess whether the bean is subject to post-processing
 * @return the object obtained from the FactoryBean
 * @throws BeanCreationException if FactoryBean object creation failed
 * @see org.springframework.beans.factory.FactoryBean#getObject()
 */
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
   
   // factory是单例的同时,factory还得已经被实例化
   if (factory.isSingleton() && containsSingleton(beanName)) {
   
      synchronized (getSingletonMutex()) {
   
         // 再次尝试从缓存中获取bean
         Object object = this.factoryBeanObjectCache.get(beanName);
         if (object == null) {
   
            // 委托doGetObjectFromFactoryBean方法产生bean
            object = doGetObjectFromFactoryBean(factory, beanName);
            // Only post-process and store if not put there already during getObject() call above
            // (e.g. because of circular reference processing triggered by custom getBean calls)
            // 再次判断缓存中是否有
            Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
            if (alreadyThere != null) {
   
               object = alreadyThere;
            }
            else {
   
               if (shouldPostProcess) {
   
                  if (isSingletonCurrentlyInCreation(beanName)) {
   
                     // Temporarily return non-post-processed object, not storing it yet..
                     return object;
                  }
                  beforeSingletonCreation(beanName);
                  try {
   
                     // 调用ObjectFactory的后处理器
                     object = postProcessObjectFromFactoryBean(object, beanName);
                  }
                  catch (Throwable ex) {
   
                     throw new BeanCreationException(beanName,
                           "Post-processing of FactoryBean's singleton object failed", ex);
                  }
                  finally {
   
                     afterSingletonCreation(beanName);
                  }
               }
               // 单例模式下:已经加载的bean要记录下来,便于下次复用
               if (containsSingleton(beanName)) {
   
                  this.factoryBeanObjectCache.put(beanName, object);
               }
            }
         }
         return object;
      }
   }
   else {
   
      Object object = doGetObjectFromFactoryBean(factory, beanName);
      if (shouldPostProcess) {
   
         try {
   
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
   
            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
         }
      }
      return object;
   }
}

如果返回的 bean 是单例的,就必须保证全局唯一,同时不可重复创建,可以使用缓存来提高性能,也就是说加载过就记录下来以便于下次复用。如果返回的 bean 不是单例的,则直接创建 bean

Spring是怎么进行保证单例模式下 bean 的全局唯一呢?在代码 16 和 19 行,分别在创建 bean 前后进行双重判断缓存中是否能通过 beanName 获取到实例。这里的缓存就是 this.factoryBeanObjectCache 这个 ConcurrentHashMap 。该方法在创建完成 bean 后,最后会将其添加至缓存。

我们大致讲了 getObjectFromFactoryBean() 方法的前面和末尾的流程,其中创建 bean 的工作实际交给了 doGetObjectFromFactoryBean(factory, beanName) 方法去完成。

/**
 * Obtain an object to expose from the given FactoryBean.
 * @param factory the FactoryBean instance
 * @param beanName the name of the bean
 * @return the object obtained from the FactoryBean
 * @throws BeanCreationException if FactoryBean object creation failed
 * @see org.springframework.beans.factory.FactoryBean#getObject()
 */
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
      throws BeanCreationException {
   

   Object object;
   try {
   
      // 需要权限认证
      if (System.getSecurityManager() != null) {
   
         AccessControlContext acc = getAccessControlContext();
         try {
   
            object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
         }
         catch (PrivilegedActionException pae) {
   
            throw pae.getException();
         }
      }
      else {
   
         // 获取bean
         object = factory.getObject();
      }
   }
   catch (FactoryBeanNotInitializedException ex) {
   
      throw new BeanCurrentlyInCreationException(beanName, ex.toString());
   }
   catch (Throwable ex) {
   
      throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
   }

   // Do not accept a null value for a FactoryBean that's not fully<

本文标签: 源码加载Springbean