• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

死磕Spring之IoC篇 – 开启 Bean 的加载

JAVA相关 月圆吖 2847次浏览 0个评论

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读

Spring 版本:5.1.14.RELEASE

开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

该系列其他文章请查看:《死磕 Spring 之 IoC 篇 – 文章导读》

开启 Bean 的加载

前面的一些列文章对面向资源(XML、Properties)面向注解定义的 Bean 是如何被解析成 BeanDefinition(Bean 的“前身”),并保存至 BeanDefinitionRegistry 注册中心里面,实际也是通过 ConcurrentHashMap 进行保存。

Spring 底层 IoC 容器 DefaultListableBeanFactory,实现了 BeanFactory 和 BeanDefinitionRegistry 接口,这个时候它处于“就绪状态”,当我们显示或者隐式地调用 getBean(...) 方法时,会触发加载 Bean 阶段,获取对应的 Bean。在该方法中,如果是单例模式会先从缓存中获取,已有则直接返回,没有则根据 BeanDefinition 开始初始化这个 Bean。

BeanFactory 体系结构

先来看看 BeanFactory 接口的继承关系

死磕Spring之IoC篇 - 开启 Bean 的加载

简单描述这些接口:

  • org.springframework.beans.factory.BeanFactory,Spring IoC 容器最基础的接口,提供依赖查找单个 Bean 的功能

  • org.springframework.beans.factory.ListableBeanFactory,继承 BeanFactory 接口,提供依赖查找多个 Bean 的功能

  • org.springframework.beans.factory.HierarchicalBeanFactory,继承 BeanFactory 接口,提供获取父 BeanFactory 的功能,具有层次性

  • org.springframework.beans.factory.config.ConfigurableBeanFactory,继承 HierarchicalBeanFactory 接口,提供可操作内部相关组件的功能,具有可配置性

  • org.springframework.beans.factory.config.AutowireCapableBeanFactory,继承 BeanFactory 接口,提供可注入的功能,支持依赖注入

  • org.springframework.beans.factory.config.ConfigurableListableBeanFactory,继承上面所有接口,综合所有特性,还提供可提前初始化所有单例 Bean 的功能

通过这些接口的名称可以大致了解其用意,接下来我们来看看它们的实现类的继承关系

死磕Spring之IoC篇 - 开启 Bean 的加载

简单描述这些实现类:

  • org.springframework.beans.factory.support.AbstractBeanFactory 抽象类,实现 ConfigurableBeanFactory 接口,基础实现类,Bean 的创建过程交由子类实现
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 抽象类,继承 AbstractBeanFactory,实现 AutowireCapableBeanFactory 接口,完成 Bean 的创建
  • org.springframework.beans.factory.support.DefaultListableBeanFactory,Spring 底层 IoC 容器,依赖注入的底层实现

其他的接口和类和 BeanDefinition 注册中心,别名注册中心,单例 Bean 注册中心相关;右下角的 ApplicationContext 与 Spring 应用上下文有关,它的整个体系这里不做展述,在后面的文章进行分析

AbstractBeanFactory

org.springframework.beans.factory.support.AbstractBeanFactory 抽象类,实现 ConfigurableBeanFactory 接口,BeanFactory 的基础实现类,提供依赖查找方法,可获取 Bean 对象,接下来我们来看看依赖查找的实现

getBean 方法

getBean(String name) 方法,根据名称获取 Bean,当然还有许多重载方法,如下:

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
}

public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
        throws BeansException {
    return doGetBean(name, requiredType, args, false);
}

最终都会调用 doGetBean(...) 这个方法

当我们显示或者隐式地调用这个方法时,会触发 Bean 的加载;你是否会有疑问,我们使用 Spring 的过程中并不会调用这个方法去获取 Bean,那这个方法会被谁调用呢?在 ConfigurableListableBeanFactory 接口中提供提前初始化所有单例 Bean 的功能,在 Spring 应用上下文(ApplicationContext)刷新阶段会提前初始化所有的单例 Bean,这个提前初始化也是调用 getBean 这个方法,这部分内容在后续分析 Spring 应用上下文的生命周期会讲到

【核心】doGetBean 方法

doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) 方法,获取一个 Bean,方法如下:

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

    // <1> 获取 `beanName`
    // 因为入参 `name` 可能是别名,也可能是 FactoryBean 类型 Bean 的名称(`&` 开头,需要去除)
    // 所以需要获取真实的 beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    // <2> 先从缓存(仅缓存单例 Bean )中获取 Bean 对象,这里缓存指的是 `3` 个 Map
    // 缓存中也可能是正在初始化的 Bean,可以避免**循环依赖注入**引起的问题
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    // <3> 若从缓存中获取到对应的 Bean,且 `args` 参数为空
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // <3.1> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
        // 否则,调用 FactoryBean#getObject() 获取目标对象
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    // 缓存中没有对应的 Bean,则开启 Bean 的加载
    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // <4> 如果**非单例模式**下的 Bean 正在创建,这里又开始创建,表明存在循环依赖,则直接抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // <5> 如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            // <5.1> 获取 `beanName`,因为可能是别名,则进行处理
            // 和第 `1` 步不同,不需要对 `&` 进行处理,因为进入父容器重新依赖查找
            String nameToLookup = originalBeanName(name);
            // <5.2> 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理
            // 否则,就是非 Spring IoC 容器,根据参数调用相应的 `getBean(...)`方法
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        // <6> 如果不是仅仅做类型检查,则表示需要创建 Bean,将 `beanName` 标记为已创建过
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // <7> 从容器中获取 `beanName` 对应的的 RootBeanDefinition(合并后)
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 检查是否为抽象类
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            // <8> 获取当前正在创建的 Bean 所依赖对象集合(`depends-on` 配置的依赖)
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    // <8.1> 检测是否存在循环依赖,存在则抛出异常
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // <8.2> 将 `beanName` 与 `dep` 之间依赖的关系进行缓存
                    registerDependentBean(dep, beanName);
                    try {
                        // <8.3> 先创建好依赖的 Bean(重新调用 `getBean(...)` 方法)
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            // <9> 开始创建 Bean,不同模式创建方式不同
            if (mbd.isSingleton()) { // <9.1> 单例模式
                /*
                 * <9.1.1> 创建 Bean,成功创建则进行缓存,并移除缓存的早期对象
                 * 创建过程实际调用的下面这个 `createBean(...)` 方法
                 */
                sharedInstance = getSingleton(beanName,
                        // ObjectFactory 实现类
                        () -> {
                            try {
                                // **【核心】** 创建 Bean
                                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.
                                // 如果创建过程出现异常,则显式地从缓存中删除当前 Bean 相关信息
                                // 在单例模式下为了解决循环依赖,创建过程会缓存早期对象,这里需要进行删除
                                destroySingleton(beanName);
                                throw ex;
                            }
                });
                // <9.1.2> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
                // 否则,调用 FactoryBean#getObject() 获取目标对象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // <9.2> 原型模式
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    // <9.2.1> 将 `beanName` 标记为原型模式正在创建
                    beforePrototypeCreation(beanName);
                    // <9.2.2> **【核心】** 创建 Bean
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // <9.2.3> 将 `beanName` 标记为不在创建中,照应第 `9.2.1` 步
                    afterPrototypeCreation(beanName);
                }
                // <9.2.4> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
                // 否则,调用 FactoryBean#getObject() 获取目标对象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            // <9.3> 其他模式
            else {
                // <9.3.1> 获取该模式的 Scope 对象 `scope`,不存在则抛出异常
                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 {
                    // <9.3.1> 从 `scope` 中获取 `beanName` 对应的对象(看你的具体实现),不存在则执行**原型模式**的四个步骤进行创建
                    Object scopedInstance = scope.get(beanName, () -> {
                        // 将 `beanName` 标记为原型模式正在创建
                        beforePrototypeCreation(beanName);
                        try {
                            // **【核心】** 创建 Bean
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            // 将 `beanName` 标记为不在创建中,照应上一步
                            afterPrototypeCreation(beanName);
                        }
                    });
                    // 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
                    // 否则,调用 FactoryBean#getObject() 获取目标对象
                    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;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    // <10> 如果入参 `requiredType` 不为空,并且 Bean 不是该类型,则需要进行类型转换
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            // <10.1> 通过类型转换机制,将 Bean 转换成 `requiredType` 类型
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            // <10.2> 转换后的 Bean 为空则抛出异常
            if (convertedBean == null) {
                // 转换失败,抛出 BeanNotOfRequiredTypeException 异常
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            // <10.3> 返回类型转换后的 Bean 对象
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    // <11> 返回获取到的 Bean
    return (T) bean;
}

这个方法的处理过程有点长,如下:

  1. 获取 beanName,因为入参 name 可能是别名,也可能是 FactoryBean 类型 Bean 的名称(& 开头,需要去除),所以需要获取真实的 beanName

  2. 先从缓存(仅缓存单例 Bean )中获取 Bean 对象,这里缓存指的是 3 个 Map;缓存中也可能是正在初始化的 Bean,可以避免循环依赖注入引起的问题

  3. 若从缓存中获取到对应的 Bean,且 args 参数为空

    1. 【同】调用 getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) 方法

      获取 Bean 的目标对象,scopedInstance 非 FactoryBean 类型直接返回,否则,调用 FactoryBean#getObject() 获取目标对象

缓存中没有对应的 Bean,则开启 Bean 的加载

  1. 如果非单例模式下的 Bean 正在创建,这里又开始创建,表明存在循环依赖,则直接抛出异常

  2. 如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)

    1. 获取 beanName,因为可能是别名,则进行处理,和第 1 步不同,不需要对 & 进行处理,因为进入父容器重新依赖查找
    2. 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理;否则,就是非 Spring IoC 容器,根据参数调用相应的 getBean(...)方法
  3. 如果不是仅仅做类型检查,则表示需要创建 Bean,将 beanName 标记为已创建过,在后面的循环依赖检查中会使用到

  4. 从容器中获取 beanName 对应的的 RootBeanDefinition(合并后),调用 getMergedLocalBeanDefinition(String beanName) 方法

  5. 获取当前正在创建的 Bean 所依赖对象集合(depends-on 配置的依赖)

    1. 检测是否存在循环依赖,存在则抛出异常
    2. beanNamedep 之间依赖的关系进行缓存
    3. 先创建好依赖的 Bean(重新调用 getBean(...) 方法)
  1. 开始创建 Bean,不同模式创建方式不同

    1. 单例模式

      1. 创建 Bean,成功创建则进行缓存,并移除缓存的早期对象,调用 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法

        【核心】入参的 ObjectFactory 实现类就是调用的 AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) 方法

      2. 【同】 和上面的 3.1 相同操作

    2. 原型模式

      1. beanName 标记为非单例模式正在创建
      2. 【核心】 创建 Bean,调用 AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) 方法
      3. beanName 标记为不在创建中,照应第 9.2.1
      4. 【同】 和上面的 3.1 相同操作
    3. 其他模式

      1. 获取该模式的 Scope 对象 scope,不存在则抛出异常
      2. scope 中获取 beanName 对应的对象(看你的具体实现),不存在则执行原型模式的四个步骤进行创建
  1. 如果入参 requiredType 不为空,并且 Bean 不是该类型,则需要进行类型转换

    1. 通过类型转换机制,将 Bean 转换成 requiredType 类型
    2. 转换后的 Bean 为空则抛出异常
    3. 返回类型转换后的 Bean 对象
  2. 返回获取到的 Bean

概括:

  • 可以看到这个方法加载 Bean 的过程中,会先从缓存中获取单例模式的 Bean;

  • 不管是从缓存中获取的还是新创建的,都会进行处理,如果是 FactoryBean 类型则调用其 getObject() 获取目标对象;

  • BeanFactory 可能有父容器,如果当前容器找不到 BeanDefinition 则会尝试让父容器创建;

  • 创建 Bean 的任务交由 AbstractAutowireCapableBeanFactory 去完成;

  • 如果获取到的 Bean 不是我们想要类型,会通过类型转换机制转换成目标类型

接下来依次分析上述过程的相关步骤(doGetBean(...)

1. 获取 beanName

对应代码段:

// AbstractBeanFactory.java
final String beanName = transformedBeanName(name);

因为入参 name 可能是别名,也可能是 FactoryBean 类型 Bean 的名称(& 开头,需要去除),所以需要进行一番转换,如下:

// AbstractBeanFactory.java
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.java
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        return name;
    }
    // 获取 name 对应的 beanName,
    // 不为 null 则返回 `transformedBeanNameCache` 缓存中对应的 beanName,
    // 为 null 则对 name 进行处理,将前缀 '&' 去除,直至没有 '&',然后放入 `transformedBeanNameCache` 缓存中,并返回处理后的 beanName
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}
// SimpleAliasRegistry.java
public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    // 循环,从 aliasMap 中,获取到最终的 beanName
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

过程并不复杂,先将前缀 & 去除(如果存在),如果是别名则获取对应的 beanName

定义了一个 FactoryBean 类型的 Bean,名称为 user,通过 user 获取 Bean,获取到的是 FactoryBean#getObject() 返回的对象(只会被调用一次)

通过 &user 获取 Bean,获取到的是 FactoryBean 本身这个对象

2. 从缓存中获取单例 Bean

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
Object sharedInstance = getSingleton(beanName);

单例模式的 Bean 被创建后会缓存,为了避免循环依赖注入,在创建过程会临时缓存正在创建的 Bean(早期 Bean),在后续文章会讲到,从缓存中获取对象过程如下:

// DefaultSingletonBeanRegistry.java

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // <1> **【一级 Map】**从单例缓存 `singletonObjects` 中获取 beanName 对应的 Bean
    Object singletonObject = this.singletonObjects.get(beanName);
    // <2> 如果**一级 Map**中不存在,且当前 beanName 正在创建
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // <2.1> 对 `singletonObjects` 加锁
        synchronized (this.singletonObjects) {
            // <2.2> **【二级 Map】**从 `earlySingletonObjects` 集合中获取,里面会保存从 **三级 Map** 获取到的正在初始化的 Bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            // <2.3> 如果**二级 Map** 中不存在,且允许提前创建
            if (singletonObject == null && allowEarlyReference) {
                // <2.3.1> **【三级 Map】**从 `singletonFactories` 中获取对应的 ObjectFactory 实现类
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                // 如果从**三级 Map** 中存在对应的对象,则进行下面的处理
                if (singletonFactory != null) {
                    // <2.3.2> 调用 ObjectFactory#getOject() 方法,获取目标 Bean 对象(早期半成品)
                    singletonObject = singletonFactory.getObject();
                    // <2.3.3> 将目标对象放入**二级 Map**
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // <2.3.4> 从**三级 Map**移除 `beanName`
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    // <3> 返回从缓存中获取的对象
    return singletonObject;
}

过程如下:

  1. 【一级 Map】从单例缓存 singletonObjects 中获取 beanName 对应的 Bean
  2. 如果一级 Map中不存在,且当前 beanName 正在创建
    1. singletonObjects 加锁
    2. 【二级 Map】earlySingletonObjects 集合中获取,里面会保存从 三级 Map 获取到的正在初始化的 Bean
    3. 如果二级 Map 中不存在,且允许提前创建
      1. 【三级 Map】singletonFactories 中获取对应的 ObjectFactory 实现类,如果从三级 Map 中存在对应的对象,则进行下面的处理
      2. 调用 ObjectFactory#getOject() 方法,获取目标 Bean 对象(早期半成品)
      3. 将目标对象放入二级 Map
      4. 三级 Map移除 beanName
  3. 返回从缓存中获取的对象

这个过程对应《深入了解 Spring IoC(面试题)》中的BeanFactory 是如何处理循环依赖问题

3. FactoryBean 的处理

一般情况下,Spring 通过反射机制利用 Bean 的 beanClass 属性指定实现类来实例化 Bean。某些情况下,Bean 的实例化过程比较复杂,如果按照传统的方式,则需要提供大量的配置信息,配置方式的灵活性有限,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂 Bean 接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。

FactoryBean 接口对于 Spring 框架本身也非常重要,其内部就提供了大量 FactoryBean 的实现。它们隐藏了实例化过程中一些复杂细节,给上层应用带来了便利。

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

不管是从缓存中获取的还是新创建的,都会调用这个方法进行处理,如果是 FactoryBean 类型则调用其 getObject() 获取目标对象

getObjectForBeanInstance 方法

// AbstractBeanFactory.java
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, 
                                          @Nullable RootBeanDefinition mbd) {
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // <1> 若 `name` 以 `&` 开头,说明想要获取 FactoryBean,则校验其**正确性**
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        // <1.1> 如果是 NullBean 空对象,则直接返回
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        // <1.2> 如果不是 FactoryBean 类型,则抛出异常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        }
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the caller actually wants a reference to the factory.
    // 到这里我们就有了一个 Bean,可能是一个正常的 Bean,也可能是一个 FactoryBean
    // 如果是 FactoryBean,则需要通过其 getObject() 方法获取目标对象

    // <2> 如果 `beanInstance` 不是 FactoryBean 类型,不需要再处理则直接返回
    // 或者(表示是 FactoryBean 类型) `name` 以 `&` 开头,表示你想要获取实际 FactoryBean 对象,则直接返回
    // 还不符合条件的话,表示是 FactoryBean,需要获取 getObject() 返回目标对象
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    // <3> 如果入参没有传 BeanDefinition,则从 `factoryBeanObjectCache` 缓存中获取对应的 Bean 对象
	// 入参传了 BeanDefinition 表示这个 Bean 是刚创建的,不走缓存,需要调用其 getObject() 方法获取目标对象
	// `factoryBeanObjectCache`:FactoryBean#getObject() 调用一次后返回的目标对象缓存在这里
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    // <4> 若第 `3` 步获取的对象为空,则需要调用 FactoryBean#getObject() 获得对象
    if (object == null) {
        // Return bean instance from factory.
        // <4.1> 将 `beanInstance` 转换成 FactoryBean 类型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        // <4.2> 如果入参没有传 BeanDefinition 并且当前容器存在对应的 BeanDefinition
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 获取对应的 RootBeanDefinition(合并后)
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用户定义的(不是 Spring 创建解析出来的)
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        // <4.3> **【核心】**通过 FactoryBean 获得目标对象,单例模式会缓存在 `factoryBeanObjectCache` 中
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

过程如下:

  1. name& 开头,说明想要获取 FactoryBean,则校验其正确性

    1. 如果是 NullBean 空对象,则直接返回
    2. 如果不是 FactoryBean 类型,则抛出异常
  2. 如果 beanInstance 不是 FactoryBean 类型,不需要再处理则直接返回;或者(表示是 FactoryBean 类型) name& 开头,表示你想要获取实际 FactoryBean 对象,则直接返回;还不符合条件的话,表示是 FactoryBean,需要获取 getObject() 返回目标对象,往下处理

  3. 如果入参没有传 BeanDefinition,则从 factoryBeanObjectCache 缓存中获取对应的 Bean 对象,如下:

    // FactoryBeanRegistrySupport.java
    protected Object getCachedObjectForFactoryBean(String beanName) {
        return this.factoryBeanObjectCache.get(beanName);
    }
    

    factoryBeanObjectCache:FactoryBean#getObject() 调用一次后返回的目标对象缓存在这里

    入参传了 BeanDefinition 表示这个 Bean 是刚创建的,不走缓存,需要调用其 getObject() 方法获取目标对象

  4. 若第 3 步获取的对象为空,则需要调用 FactoryBean#getObject() 获得对象

    1. beanInstance 转换成 FactoryBean 类型
    2. 如果入参没有传 BeanDefinition 并且当前容器存在对应的 BeanDefinition,则获取对应的 RootBeanDefinition(合并后)
    3. 【核心】通过 FactoryBean 获得目标对象,单例模式会缓存在 factoryBeanObjectCache 中,调用 getObjectFromFactoryBean(FactoryBean<?>, String, boolean) 方法

getObjectFromFactoryBean 方法

getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 方法,获取 FactoryBean 的目标对象,方法如下:

// FactoryBeanRegistrySupport.java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // <1> `factory` 为单例模式,且单例 Bean 缓存中存在 `beanName` 对应的 FactoryBean 对象
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) { // <1.1> 获取单例锁,保证安全
            // <1.2> 从 `factoryBeanObjectCache` 缓存中获取 FactoryBean#getObject() 创建的目标对象
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // <1.3> 则根据 `factory` 获取目标对象,调用 FactoryBean#getObject() 方法
                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)
                // <1.4> 这里再进行一次校验,看是否在缓存中存在 FactoryBean 创建的目标对象,如果有则优先从缓存中获取
                // 保证 FactoryBean#getObject() 只能被调用一次
                // 没有的话,则对刚获取到的目标对象进行接下来的处理
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    // <1.5> 是否需要后续处理,这个 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
                    if (shouldPostProcess) {
                        // <1.5.1> 若该 FactoryBean 处于创建中,则直接返回这个目标对象,不进行接下来的处理过程
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        // <1.5.2> 前置处理,将 `beanName` 标志为正在创建
                        beforeSingletonCreation(beanName);
                        try {
                            // <1.5.3> 对通过 FactoryBean 获取的目标对象进行后置处理
                            // 遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            // <1.5.4> 后置处理,将 `beanName` 标志为不在创建中
                            afterSingletonCreation(beanName);
                        }
                    }
                    // <1.6> 如果缓存中存在 `beanName` 对应的 FactoryBean 对象
                    // 上面不是判断了吗?也可能在上面的处理过程会有所变化,所以这里在做一层判断
                    // 目的:缓存 FactoryBean 创建的目标对象,则需要保证 FactoryBean 本身这个对象存在缓存中
                    if (containsSingleton(beanName)) {
                        // <1.6.1> 将这个 FactoryBean 创建的目标对象保存至 `factoryBeanObjectCache`
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            // <1.7> 返回 FactoryBean 创建的目标对象
            return object;
        }
    }
    // <2> `factory` 非单例模式,或单例 Bean 缓存中不存在 `beanName` 对应的 FactoryBean 对象
    else {
        // <2.1> 则根据 `factory` 获取目标对象,调用 FactoryBean#getObject() 方法
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        // <2.2> 是否需要后续处理,这个 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
        if (shouldPostProcess) {
            try {
                // <2.2.1> 对通过 FactoryBean 获取的目标对象进行后置处理
                // 遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        // <2.3> 返回 FactoryBean 创建的目标对象,非单例模式不会进行缓存
        return object;
    }
}

过程如下:

  1. factory 为单例模式,且单例 Bean 缓存中存在 beanName 对应的 FactoryBean 对象

    1. 获取单例锁,保证安全

    2. factoryBeanObjectCache 缓存中获取 FactoryBean#getObject() 创建的目标对象

    3. 则根据 factory 获取目标对象,调用 FactoryBean#getObject() 方法(反射机制)

    4. 这里再进行一次校验(第 1.2 已经判断过),看是否在缓存中存在 FactoryBean 创建的目标对象,如果有则优先从缓存中获取,保证 FactoryBean#getObject() 只能被调用一次;没有的话,则对刚获取到的目标对象进行接下来的处理

    5. 是否需要后续处理,这个 FactoryBean 的 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是

      1. 若该 FactoryBean 处于创建中,则直接返回这个目标对象,不进行接下来的处理过程

      2. 前置处理,将 beanName 标志为正在创建

      3. 对通过 FactoryBean 获取的目标对象进行后置处理,遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)

      4. 后置处理,将 beanName 标志为不在创建中

      5. 如果缓存中存在 beanName 对应的 FactoryBean 对象,上面不是判断了吗(第 1 步判断过)?

        也可能在上面的处理过程会有所变化,所以这里在做一层判断,目的:缓存 FactoryBean 创建的目标对象,则需要保证 FactoryBean 本身这个对象存在缓存中

        1. 将这个 FactoryBean 创建的目标对象保存至 factoryBeanObjectCache
      6. 返回 FactoryBean 创建的目标对象

  2. factory 非单例模式,或单例 Bean 缓存中不存在 beanName 对应的 FactoryBean 对象

    1. 则根据 factory 获取目标对象,调用 FactoryBean#getObject() 方法(反射机制)
    2. 是否需要后续处理,这个 FactoryBean 的 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
      1. 对通过 FactoryBean 获取的目标对象进行后置处理,遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
    3. 返回 FactoryBean 创建的目标对象,非单例模式不会进行缓存

概括:调用 FactoryBean#getObject() 获取目标对象,单例模式会缓存起来;过程中 Sping 考虑到各种情况,例如保证单例模式下 FactoryBean#getObject() 只调用一次,是否需要进行后置处理。

4. 非单例模式依赖检查

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    return (curVal != null && (curVal.equals(beanName) // 相等
            || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); // 包含
}

prototypesCurrentlyInCreation 中保存非单例模式下正在创建的 Bean 的名称,这里又重新创建,表示出现循环依赖,则直接抛出异常

Spring 对于非单例模式的 Bean 无法进行相关缓存,也就无法处理循环依赖的情况,选择了直接抛出异常

5. BeanFactory 层次性加载 Bean 策略

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    // <5.1> 获取 `beanName`,因为可能是别名,则进行处理
    // 和第 `1` 步不同,不需要对 `&` 进行处理,因为进入父容器重新依赖查找
    String nameToLookup = originalBeanName(name);
    // <5.2> 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理
    // 否则,就是非 Spring IoC 容器,根据参数调用相应的 `getBean(...)`方法
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
        return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
        return (T) parentBeanFactory.getBean(nameToLookup);
    }
}

如果当前 BeanFactory 没有对应的 BeanDefinition,也就无法创建 Bean,但是如果存在 BeanFactory,则将接下来的操作交由 BeanFactory,找不到会层层找上去,如果所有 BeanFactory 都找不到对应的 BeanDefinition 最终会抛出异常。

6. 将 beanName 标记为已创建

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
// <6> 如果不是仅仅做类型检查,则表示需要创建 Bean,将 `beanName` 标记为已创建过
if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

如果不是仅仅做类型检查,则调用 markBeanAsCreated(String beanName) 方法,如下:

// AbstractBeanFactory.java
protected void markBeanAsCreated(String beanName) {
    // 没有创建
    if (!this.alreadyCreated.contains(beanName)) {
        // 加上全局锁
        synchronized (this.mergedBeanDefinitions) {
            // 再次检查一次:DCL 双检查模式
            if (!this.alreadyCreated.contains(beanName)) {
                // Let the bean definition get re-merged now that we're actually creating
                // the bean... just in case some of its metadata changed in the meantime.
                // 从 mergedBeanDefinitions 中删除 beanName,并在下次访问时重新创建它
                clearMergedBeanDefinition(beanName);
                // 添加到已创建 bean 集合中
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

将这个 beanName 保存在 alreadyCreated 集合中(SetFromMap),在后面的循环依赖检查中会使用到

7. 获取 RootBeanDefinition

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
// <7> 从容器中获取 `beanName` 对应的的 RootBeanDefinition(合并后)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查是否为抽象类
checkMergedBeanDefinition(mbd, beanName, args);

因为我们定义的 Bean 大多数都被 Spring 解析成 GenericBeanDefinition 类型,具有父子关系,则需要获取最终的 BeanDefinition;如果存在父子关系,则会进行一系列的合并,转换成 RootBeanDefinition 对象,调用 getMergedLocalBeanDefinition(String beanName) 方法,如下:

// AbstractBeanFactory.java
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // Quick check on the concurrent map first, with minimal locking.
    // 从 `mergedBeanDefinitions` 缓存中获取合并后的 RootBeanDefinition,存在则直接返回
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    if (mbd != null) {
        return mbd;
    }
    // 获取 BeanDefinition 并转换成,如果存在父子关系则进行合并
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
        throws BeanDefinitionStoreException {
    return getMergedBeanDefinition(beanName, bd, null);
}

protected RootBeanDefinition getMergedBeanDefinition(
        String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
        throws BeanDefinitionStoreException {

    // 加锁
    synchronized (this.mergedBeanDefinitions) {
        RootBeanDefinition mbd = null;

        // Check with full lock now in order to enforce the same merged instance.
        if (containingBd == null) {
            mbd = this.mergedBeanDefinitions.get(beanName);
        }

        if (mbd == null) {
            // 如果没有父类则直接转换成 RootBeanDefinition 对象
            if (bd.getParentName() == null) {
                // Use copy of given root bean definition.
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                    mbd = new RootBeanDefinition(bd);
                }
            }
            // 有父类则进行合并
            else {
                // Child bean definition: needs to be merged with parent.
                BeanDefinition pbd;
                try {
                    // 获取父类的对应的 BeanDefinition 对象
                    String parentBeanName = transformedBeanName(bd.getParentName());
                    if (!beanName.equals(parentBeanName)) {
                        pbd = getMergedBeanDefinition(parentBeanName);
                    }
                    else {
                        BeanFactory parent = getParentBeanFactory();
                        if (parent instanceof ConfigurableBeanFactory) {
                            pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            throw new NoSuchBeanDefinitionException(parentBeanName,
                                    "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                    "': cannot be resolved without an AbstractBeanFactory parent");
                        }
                    }
                }
                catch (NoSuchBeanDefinitionException ex) {
                    throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                            "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                }
                // Deep copy with overridden values.
                mbd = new RootBeanDefinition(pbd);
                // 父子合并
                mbd.overrideFrom(bd);
            }

            // Set default singleton scope, if not configured before.
            if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
            }

            // A bean contained in a non-singleton bean cannot be a singleton itself.
            // Let's correct this on the fly here, since this might be the result of
            // parent-child merging for the outer bean, in which case the original inner bean
            // definition will not have inherited the merged outer bean's singleton status.
            if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                mbd.setScope(containingBd.getScope());
            }

            // Cache the merged bean definition for the time being
            // (it might still get re-merged later on in order to pick up metadata changes)
            if (containingBd == null && isCacheBeanMetadata()) {
                // 放入缓存中
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }

        return mbd;
    }
}

过程大致如下:

  1. mergedBeanDefinitions 缓存中获取合并后的 RootBeanDefinition,存在则直接返回,不存在则进行后面的操作
  2. 获取合并后的 RootBeanDefinition 对象,逻辑并不复杂,将一些属性进行合并;这里对于 BeanDefinition 的获取也存在层次性查找策略;注意,如果一个单例 BeanDefinition 包含在非单例 BeanDefinition,那么会变成非单例 Bean

后续还会对合并后的 RootBeanDefinition 对象进行检查,如果是抽象的,则抛出异常

8. 依赖 Bean 的处理

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
// Guarantee initialization of beans that the current bean depends on.
// <8> 获取当前正在创建的 Bean 所依赖对象集合(`depends-on` 配置的依赖)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        // <8.1> 检测是否存在循环依赖,存在则抛出异常
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        // <8.2> 将 `beanName` 与 `dep` 之间依赖的关系进行缓存
        registerDependentBean(dep, beanName);
        try {
            // <8.3> 先创建好依赖的 Bean(重新调用 `getBean(...)` 方法)
            getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}
  • 每个 Bean 不一定是单独工作的,可以通过 depends-on 配置依赖的 Bean,其他 Bean 也可以依赖它

  • 对于依赖的 Bean,会优先加载,所以在 Spring 的加载顺序中,在初始化某个 Bean 的时候,首先会初始化这个 Bean 的依赖

isDependent 方法

在初始化依赖的 Bean 之前,会调用 isDependent(String beanName, String dependentBeanName) 方法,判断是否出现循环依赖,方法如下:

DefaultSingletonBeanRegistry.java
protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    // <1> `alreadySeen` 中已经检测过该 `beanName` 则直接返回 `false`
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // <2> 获取最终的 `beanName`,因为可能是别名,需要进行相关处理
    String canonicalName = canonicalName(beanName);
    // <3> 从 `dependentBeanMap` 中获取依赖 `beanName` 的 Bean 集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    // <4> 没有 Bean 依赖该 `beanName`,也就不存在循环依赖,返回 `false`
    if (dependentBeans == null) {
        return false;
    }
    // <5> 依赖 `beanName` 的 Bean 们包含 `dependentBeanName`,表示出现循环依赖,返回 `true`
    if (dependentBeans.contains(dependentBeanName)) {
        // `beanName` 与 `dependentBeanName` 相互依赖
        return true;
    }
    // <6> 对依赖该 `beanName` 的 Bean 们进行检查,看它们是否与 `dependentBeanName` 存在依赖,递归处理
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

过程大致如下:

  1. alreadySeen 中已经检测过该 beanName 则直接返回 false
  2. 获取最终的 beanName,因为可能是别名,需要进行相关处理
  3. dependentBeanMap 中获取依赖 beanName 的 Bean 集合
  4. 没有 Bean 依赖该 beanName,也就不存在循环依赖,返回 false
  5. 依赖 beanName 的 Bean 们包含 dependentBeanName,表示出现循环依赖,返回 true
  6. 对依赖该 beanName 的 Bean 们进行检查,看它们是否与 dependentBeanName 存在依赖,递归处理

判断是否出现循环依赖的过程有点绕,需要花点时间理解一下。例如:现在检查 A ->(依赖)B,看是否出现循环依赖,我获取到依赖 A 的所有 Bean,看 B 是否依赖这里面的 Bean,如果出现 A -> B -> C -> A,那就出现循环依赖了。如果出现循环依赖,则会抛出异常,所以我们说 Spring 处理了单例 Bean 的循环依赖注入比较好一点。

registerDependentBean 方法

beanNamedepbeanName 的依赖)之间依赖的关系进行缓存,调用 registerDependentBean(String beanName, String dependentBeanName) 方法,如下:

DefaultSingletonBeanRegistry.java
public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = canonicalName(beanName);

    // 对应关系:beanName -> 依赖 beanName 的集合
    synchronized (this.dependentBeanMap) {
        Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, 
                                                                           k -> new LinkedHashSet<>(8));
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }

    // 对应关系:beanName - > beanName 的依赖的集合
    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, 
                                                                                      k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName);
    }
}

将两者的依赖关系保存起来,目的是在 isDependent 方法中判断是否出现循环依赖

getBean 方法

加载 beanName 依赖的 Bean,同样是调用 AbstractBeanFactory#getBean(String dep) 方法,也就是本文开头讲的这个方法

9. 不同作用域的 Bean 的创建

Spring 的作用域划分为三种:单例模式、原型模式、其他模式,会依次进行判断,然后进行创建,创建过程都是一样的,主要是存储范围不一样

  • 单例模式:一个 BeanFactory 有且仅有一个实例
  • 原型模式:每次依赖查找和依赖注入生成新 Bean 对象
  • 其他模式,例如 request 作用域会将 Bean 存储在 ServletRequest 上下文中;session 作用域会将 Bean 存储在 HttpSession 中;application 作用域会将 Bean 存储在 ServletContext 中

单例模式

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
if (mbd.isSingleton()) { // <9.1> 单例模式
    /*
     * <9.1.1> 创建 Bean,成功创建则进行缓存,并移除缓存的早期对象
     * 创建过程实际调用的下面这个 `createBean(...)` 方法
     */
    sharedInstance = getSingleton(beanName,
            // ObjectFactory 实现类
            () -> {
                try {
                    // **【核心】** 创建 Bean
                    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.
                    // 如果创建过程出现异常,则显式地从缓存中删除当前 Bean 相关信息
                    // 在单例模式下为了解决循环依赖,创建过程会缓存早期对象,这里需要进行删除
                    destroySingleton(beanName);
                    throw ex;
                }
    });
    // <9.1.2> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
    // 否则,调用 FactoryBean#getObject() 获取目标对象
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

如果是单例模式,创建过程大致如下:

  1. 调用 DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法

    创建 Bean,成功创建则进行缓存,并移除缓存的早期对象,创建过程实际调用的下面这个 AbstractAutowireCapableBeanFactory#createBean(...) 方法

  2. FactoryBean 的处理,在前面 3. FactoryBean 的处理 中已经分析过

getSingleton 方法

DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法,单例模式下获取单例 Bean,如下:

// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 全局加锁
    synchronized (this.singletonObjects) {
        // <1> 从 `singletonObjects` 单例 Bean 的缓存中获取 Bean(再检查一遍),存在则直接返回,否则开始创建
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // <2> 将 `beanName` 标记为单例模式正在创建
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                /**
                 * <3> 创建 Bean,实际调用 
                 * {@link AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])} 方法
                 */
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // <4> 将 `beanName` 标记为不在创建中,照应第 `2` 步
                afterSingletonCreation(beanName);
            }
            // <5> 如果这里是新创建的单例模式 Bean,则在 `singletonObjects` 中进行缓存(无序),移除缓存的早期对象
            // 并在 `registeredSingletons` 中保存 `beanName`,保证注册顺序
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

过程大致如下:

  1. singletonObjects 单例 Bean 的缓存中获取 Bean(再检查一遍),存在则直接返回,否则开始创建
  2. beanName 标记为单例模式正在创建
  3. 【核心】创建 Bean,实际调用 AbstractAutowireCapableBeanFactory#createBean(...) 方法
  4. beanName 标记为不在创建中,照应第 2
  5. 如果这里是新创建的单例模式 Bean,则在 singletonObjects 中进行缓存(无序),移除缓存的早期对象,并在 registeredSingletons 中保存 beanName,保证注册顺序
createBean 方法

AbstractAutowireCapableBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法,创建 Bean,整个过程大致如下:

  1. Bean 的实例化
  2. 属性赋值(包括依赖注入)
  3. Aware 接口回调
  4. 调用初始化方法

上面涉及到 Bean 生命周期的大部分阶段,将会在后续的文章中依次分析

原型模式

对应代码段:

// AbstractBeanFactory.java
// <9.2> 原型模式
else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        // <9.2.1> 将 `beanName` 标记为**非单例模式**正在创建
        beforePrototypeCreation(beanName);
        // <9.2.2> **【核心】** 创建 Bean
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        // <9.2.3> 将 `beanName` 标记为不在创建中,照应第 `9.2.1` 步
        afterPrototypeCreation(beanName);
    }
    // <9.2.4> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
    // 否则,调用 FactoryBean#getObject() 获取目标对象
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

过程大致如下:

  1. beanName 标记为非单例模式正在创建
  2. 【核心】创建 Bean 也是调用 AbstractAutowireCapableBeanFactory#createBean(...) 方法,这里没有缓存,每次加载 Bean 都会创建一个对象
  3. beanName 标记为不在创建中,照应第 1
  4. FactoryBean 的处理,在前面 3. FactoryBean 的处理 中已经分析过

其他模式

对应代码段:

// AbstractBeanFactory.java
// <9.3> 其他模式
else {
    // <9.3.1> 获取该模式的 Scope 对象 `scope`,不存在则抛出异常
    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 {
        // <9.3.2> 从 `scope` 中获取 `beanName` 对应的对象(看你的具体实现),不存在则执行**原型模式**的四个步骤进行创建
        Object scopedInstance = scope.get(beanName, () -> {
            // 将 `beanName` 标记为**非单例模式**式正在创建
            beforePrototypeCreation(beanName);
            try {
                // **【核心】** 创建 Bean
                return createBean(beanName, mbd, args);
            }
            finally {
                // 将 `beanName` 标记为不在创建中,照应上一步
                afterPrototypeCreation(beanName);
            }
        });
        // 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
        // 否则,调用 FactoryBean#getObject() 获取目标对象
        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);
    }
}

过程如下:

  1. 获取该模式的 Scope 对象 scope,不存在则抛出异常
  2. scope 中获取 beanName 对应的对象(看你的具体实现),不存在则执行原型模式的四个步骤进行创建

想要自定义一个作用域,可以实现 org.springframework.beans.factory.config.Scope 接口,并往 Spring 应用上下文注册即可

10. 类型转换

对应代码段:

// AbstractBeanFactory#doGetBean(...) 方法
// <10> 如果入参 `requiredType` 不为空,并且 Bean 不是该类型,则需要进行类型转换
if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
        // <10.1> 通过类型转换机制,将 Bean 转换成 `requiredType` 类型
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        // <10.2> 转换后的 Bean 为空则抛出异常
        if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        // <10.3> 返回类型转换后的 Bean 对象
        return convertedBean;
    }
    catch (TypeMismatchException ex) {
        if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                    ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
}

如果入参 requiredType 不为空,并且 Bean 不是该类型,则需要进行类型转换,过程如下:

  1. 通过类型转换机制,将 Bean 转换成 requiredType 类型,对 Spring 的类型转换机制感兴趣的小伙伴可以自己研究,参考 org.springframework.core.convert.support.DefaultConversionService
  2. 转换后的 Bean 为空则抛出异常
  3. 返回类型转换后的 Bean 对象

总结

本文对 BeanFactory 接口的体系结构进行了分析,得知 DefaultListableBeanFactory 是 BeanFactory 的最底层实现,也就是 Spring 的底层 IoC 容器。接着分析了 AbstractBeanFactorygetBean(...) 方法,当我们显示或者隐式地调用这个方法时,会触发 Bean 的加载。上面所有小节对 Bean 的加载过程进行了分析,我已经有序地在每个小节面前添加了序号,这些序号对应着加载过程中的顺序。

不同作用域的 Bean 的创建,底层都会调用 AbstractAutowireCapableBeanFactorycreateBean(...) 方法进行创建,创建 Bean 的过程涉及到 Bean 生命周期的大部分阶段,例如实例化阶段、属性赋值阶段、Aware 接口回调阶段、初始化阶段都是在这个方法中完成的,整个创建过程将在后续的文章进行分析。


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明死磕Spring之IoC篇 – 开启 Bean 的加载
喜欢 (0)

您必须 登录 才能发表评论!

加载中……