【Spring 源码】—— IoC 之加载 Bean:parentBeanFactory 与依赖处理

若是从单列缓存中没有获取到 Bean 对象,则说明有两种状况:java

  1. 该 Bean 的 Scope 不是 Singleton
  2. 该 Bean 的 Scope 是 Singleton,可是初始化没有完成

针对这两种状况,Spring 是如何处理的呢?统一加载并完成初始化!这部份内容的篇幅较长,拆分为两部分:缓存

  • 第一部分,主要是一些检测、parentBeanFactory 以及依赖处理。 
  • 第二部分则是各个 scope 的初始化。 

代码以下:markdown

//AbstractBeanFactory.java

// <3> 由于 Spring 只解决单例模式下得循环依赖,在原型模式下若是存在循环依赖则会抛出异常。
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}

// <4> 若是当前容器中没有找到,则从父类容器中加载
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    String nameToLookup = originalBeanName(name);
    // 若是,父类容器为 AbstractBeanFactory ,直接递归查找
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
        // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
    } else if (args != null) {
        return (T)parentBeanFactory.getBean(nameToLookup, args);
        // 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
    } else if (requiredType != null) {
        return parentBeanFactory.getBean(nameToLookup, requiredType);
        // 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
    } else {
        return (T)parentBeanFactory.getBean(nameToLookup);
    }
}

// <5> 若是不是仅仅作类型检查则是建立bean,这里须要记录
if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

try {
    // <6> 从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    // 检查给定的合并的 BeanDefinition
    checkMergedBeanDefinition(mbd, beanName, args);

    // <7> 处理所依赖的 bean
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        for (String dep : dependsOn) {
            // 若给定的依赖 bean 已经注册为依赖给定的 bean
            // 即循环依赖的状况,抛出 BeanCreationException 异常
            if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            // 缓存依赖调用 TODO 芋艿
            registerDependentBean(dep, beanName);
            try {
                // 递归处理依赖 Bean
                getBean(dep);
            } catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
        }
    }
// ... 省略不少代码
}复制代码

这段代码主要处理如下几个部分:ide

  • <3> 处,原型模式循环依赖检查,若是当前 Bean 在建立,则抛出异常。详细解析见「1. 循环依赖检查」
  • <4> 处,若是 beanDefinitionMap 中不存在 beanName 的 BeanDefinition(即在 Spring bean 初始化过程当中没有加载),则尝试从 parentBeanFactory 中加载。详细解析见「2. 检查父类 BeanFactory」
  • <5> 处,判断是否为类型检查。详细解析见「3. 类型检查」
  • <6> 处,从 mergedBeanDefinitions 中获取 beanName 对应的 RootBeanDefinition 对象。若是这个 BeanDefinition 是子 Bean 的话,则会合并父类的相关属性。详细解析见「4. 获取 RootBeanDefinition」
  • <7> 处

1. 循环依赖检查

Spring 只解决单列模式下的循环依赖,对于原型模式的依赖则抛出 BeanCurrentlyInCreationException 异常post

//AbstractBeanFactory.java

// 由于 Spring 只解决单例模式下得循环依赖,在原型模式下若是存在循环依赖则会抛出异常。
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}
复制代码

调用 AbstractBeanFactory#isPrototypeCurrentlyInCreation(String beanName) 方法,判断当前 Bean 是否正在建立。代码以下:ui

//AbstractBeanFactory.java

//ThreaadLocal 缓存建立的Bean
private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation");

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    return (curVal != null &&
        (curVal.equals(beanName)|| (curVal instanceof Set && ((Set<?>)curVal).contains(beanName))));
}复制代码

ThreadLocal 存储的值在单列模式和原型模式是不同的
this

  • 单列模式存储的是 Set 集合
  • 原型模式存储的是 String

2. 检查父类 BeanFactory

若是当前容器没有找到 Bean ,就从父容器中加载。代码以下:
spa

//AbstractBeanFactory.java

// 获取父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
// 检查父容器
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // 获取原始 beanName
    String nameToLookup = originalBeanName(name);
    // 若是,父类容器为 AbstractBeanFactory ,直接递归查找
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
        // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
    } else if (args != null) {
        return (T)parentBeanFactory.getBean(nameToLookup, args);
        // 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
    } else if (requiredType != null) {
        return parentBeanFactory.getBean(nameToLookup, requiredType);
        // 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
    } else {
        return (T)parentBeanFactory.getBean(nameToLookup);
    }
}复制代码

2.1 获取父容器

获取父容器。代码以下:prototype

//AbstractBeanFactory.java

private BeanFactory parentBeanFactory;

@Override
public BeanFactory getParentBeanFactory() {
    return this.parentBeanFactory;
}复制代码

2.2 检查父容器

若父容器不为空,而且 beanDefinitionMap 中没有找到对应的 BeanDefinition 对象 。代码以下:code

//DefaultListableBeanFactory.java

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

@Override
public boolean containsBeanDefinition(String beanName) {
	Assert.notNull(beanName, "Bean name must not be null");
	return this.beanDefinitionMap.containsKey(beanName);
}复制代码

2.3 获取原始 beanName

获取原始 beanName。代码以下:

//AbstractBeanFactory.java

protected String originalBeanName(String name) {
    String beanName = transformedBeanName(name); // <x>
    if (name.startsWith(FACTORY_BEAN_PREFIX)) { // <y>
        beanName = FACTORY_BEAN_PREFIX + beanName;
    }
    return beanName;
}复制代码

  • <x> 处,AbstractBeanFactory#transformedBeanName(String name) 方法,是对 name 进行转换,获取真正的 beanName。详情解析前往《【Spring 源码】—— IoC 之开启 Bean 的加载》
  • <y> 处,若是 name 是以 "&" 开头的,则加上 "&"  ,由于在AbstractBeanFactory#transformedBeanName(String name) 方法中把  "&"  去掉,这边须要补上

2.4 委托父容器加载

这里都是委托父容器加载 Bean 的逻辑。代码以下:

// 若是,父类容器为 AbstractBeanFactory ,直接递归查找
if (parentBeanFactory instanceof AbstractBeanFactory) {
    return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
    // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
} else if (args != null) {
    return (T)parentBeanFactory.getBean(nameToLookup, args);
    // 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
} else if (requiredType != null) {
    return parentBeanFactory.getBean(nameToLookup, requiredType);
    // 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
} else {
    return (T)parentBeanFactory.getBean(nameToLookup);
}复制代码

3.类型检查

方法参数 typeCheckOnly,表示仅仅进行类型检查获取 Bean 对象。若是不是仅仅作类型检查,而是建立 Bean 对象,则须要调用 AbstractBeanFactory#markBeanAsCreated(String beanName) 方法,进行记录。代码以下:

//AbstractBeanFactory.java

// beanName -> RootBeanDefinition
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

protected void markBeanAsCreated(String beanName) {
    // 没有建立
    if (!this.alreadyCreated.contains(beanName)) {
        // 加上全局锁
        synchronized (this.mergedBeanDefinitions) {
            // 再次检查一次:DCL 双检查模式
            if (!this.alreadyCreated.contains(beanName)) {
                // 从 mergedBeanDefinitions 中删除 beanName,并在下次访问时从新建立它。
                clearMergedBeanDefinition(beanName);
                // 添加到已建立 bean 集合中
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

protected void clearMergedBeanDefinition(String beanName) {
    this.mergedBeanDefinitions.remove(beanName);
}
复制代码

4. 获取 RootBeanDefinition

//AbstractBeanFactory.java

// 从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 BeanDefinition
checkMergedBeanDefinition(mbd, beanName, args);复制代码

调用 AbstractBeanFactory#getMergedLocalBeanDefinition(String beanName) 获取 RootBeanDefinition 对象。代码以下:

//AbstractBeanFactory.java
// beanName -> RootBeanDefinition
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // 快速从缓存中获取,若是不为空,则直接返回
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    if (mbd != null) {
        return mbd;
    }
    // 若是返回的 BeanDefinition 是子类 bean 的话,则合并父类相关属性
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
复制代码
  • 若是 mergedBeanDefinitions 缓存中存在对应的 RootBeanDefinition 对象,则直接返回。
  • 不然调用AbstractBeanFactory#getMergedBeanDefinition(String beanName, BeanDefinition bd)获取 RootBeanDefinition 对象
    • 经过 AbstractBeanFactory#getBeanDefinition(String beanName) 获取 BeanDefinition 对象,若是没有找到就抛出 NoSuchBeanDefinitionException 异常。代码以下:
// DefaultListableBeanFactory.java

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

// AbstractBeanFactory.java
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
    BeanDefinition bd = this.beanDefinitionMap.get(beanName);
    if (bd == null) {
        if (logger.isTraceEnabled()) {
            logger.trace("No bean named '" + beanName + "' found in " + this);
        }
        throw new NoSuchBeanDefinitionException(beanName);
    }
    return bd;
}复制代码

5.