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】协议,转载请保留原文出处及本版权声明。
评论