Spring 获取单例流程 (二)
读完这篇文章你将会收获到
``
Spring`中`prototype`类型的`bean`` 如何做循环依赖检测``
Spring`中`singleton`类型的`bean`` 如何做循环依赖检测
前言
继上一篇文章 Spring 获取单例流程(一) 我们这次继续往下分析一下后面的流程

上一篇文章中我们说到,首先我们根据 ``name` 找到其对应的 `beanName` 、然后去缓存中看是否已经创建了/创建中这个对应的 `bean`,如果在缓存中找到了这个 `bean`、那么我们需要对这个 `bean` 可能进行一些处理,比如说用户想要的是一个普通的 `bean` 、但是在 `Spring` 缓存中找到的是一个 `factoryBean`、这个时候就要调用 `fatoryBean` 的 `getObject`` 方法以及对应的一些前置方法以及回调等。
那么如果我们在缓存中找不到这个 ``bean`` 那么流程又是怎么样?这个就是这篇文章要跟大家一起分享的
源码分析
第一步就是判断这个是否是一个 ``prototype` 类型的 `bean``,如果是并且正在创建中、那么就抛出一个循环依赖的异常
每一个 ``prototype` 的 `bean`` 创建的时候都会调用下面这个方法
``curVal` 要么是一个 `String` 要么是一个 `Set` , 而在创建 `prototype bean`` 完成之后
可以看到 ``Spring` 使用 `ThreadLocal` 去做一个循环依赖的检测、我们在 `Spring` 资源加载的源码分析里面也提及到了、也是使用 `ThreadLocal`` 进行一个资源的循环引用的检测 Spring 容器的初始化
第二步则是判断当前的 ``beanFactory` 是否有父容器(父 `beanFactory`) ,如果有并且 `beanName` 的 `beanDefinition` 不存在当前的 `beanFactory` 中,那么则尝试在父容器中去获取这个 `bean``
我们继续往下看下面的代码
第三步则是从 ``BeanDefinitionRegistry` 中获取注册的 `BeanDefinition` 继而获取这个 `bean` 所要依赖的其他 `bean` ,遍历其所依赖的 `bean`` 、判断是否循环依赖了
每一个 ``bean` 创建之前都会注册其依赖关系、主要由两个 `Map` 组成、一个是 `key` 为被依赖者,`value` 为依赖者集合,另一个则是 `key` 为依赖者,`value` 为被依赖者集合,比如说 `beanA` 依赖着 `beanB` 和 `beanC``
第四步则是去注册依赖关系,也就是往上面的两个 ``Map`` 中存放数据
最后的 ``getBean`` 则回到我们最初的起点
今天我们就先分析到这里、后续的话我们在后面的文章继续探讨。今天我们大致分析了


总结
根据参数中的 ``
name`找出对应的`beanName`、无论这个`name`是别名或者是一个`factoryBean`的`beanName``查看缓存中是否包含这个 ``
beanName`` 对象
- 先从一级缓存 ``singletonObjects`` 中看看有没有
- 然后从二级缓存 ``earlySingletonObjects``
- 都没有的话再从三级缓存 ``singletonFactories`` 中看看有没有
如果缓存中有 ``
bean`、那么我们还是需要处理一下这个`bean``
- 如果 ``Spring` 缓存中返回的 `bean` 是 `factoryBean` 、而用户也想要的是一个 `beanFactory` (参数 `name` 中的前缀是 `&`` )、那么我们直接返回
- 如果 ``Spring` 缓存中返回的 `bean` 是普通的 `bean`、而用户也想要的是一个普通的 `bean`` 、那么就直接返回
- 如果 ``Spring` 缓存中返回的 `bean` 是一个 `factoryBean` 、而用户想要的是一个普通的 `bean` 、那么我们就要从 `factoryBean` 中获取这个 `bean``
- 而从 ``factoryBean` 中获取这个 `bean` 的过程中、需要调用到前置处理、后置处理和我们常用的接口回调 `BeanPostProcessor``
如果缓存中没有 ``
bean`、则判断是否是`prototype`` 类型并且循环依赖如果没有则尝试能否在父容器中找到该 ``
bean``如果父容器也没有则获取该 ``
beanName`对应的`beanDefinition`找出其依赖的`beanName``判断该 ``
beanName`与 依赖的`beanName`是否循环依赖、没有则注册其依赖关系并调用`getBean`方法去创建依赖的`beanName``
版权声明: 本文为 InfoQ 作者【CoderLi】的原创文章。
原文链接:【http://xie.infoq.cn/article/95679b4c1a2f85c2baee1f94d】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。











评论