前言
初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着 “循环依赖,单例模式,Bean的定位加载注册,原型模式…”, 渐渐跑着跑着就变成了慢慢悠悠的走走歇歇,忽然间感觉肩膀好像被砖头砸了一下,
身后传来一句
"你张大胖减肥是不可能减肥的,就是在健身房里划划水才能维持的了生活 !" ,大胖被拍的浑身一惊, 看了眼一身运动装的 Mason, 急忙反驳道
"没有调查就没有发言权, 俺只是暂时休息下, 今天都已经跑了好几个小时了呢,倒是 Mason 你像是来假健身的…",Mason 笑笑说 "哎呀呀, 你这么厉害呢,可惟独肚子上的赘肉骗不了人啊,最近面试的怎么样?"
大胖 一脸愁容的说道: "最近招聘市场很给力,我也参加了不少面试,就是每次聊到 Spring 时被面试官三连追问 Spring是如何解决循环依赖, 而我对着个问题查了很多资料,但也就能回答个一知半解,然后就叫我回去等通知了…"
Mason 在跑步机上边跑边说 "Spring 解决循环依赖的这个场景, 其实也可以映射到生活中, 比如 你工作日睡过了又害怕迟到扣钱,就在 DD出行 App上选择一个起始地打车, 同一时间来了两辆 DD专车, 你也没有check车牌就上车了, 司机也没check你拉上就走,你一上车就聚精会神看起宅舞视频, 结果到达别人的目的地发现上错车,既迟到了又要付来回路费,那么问题来了 你为什么会上错车呢? "
大胖 挠挠头回答道: "因为睡过了怕迟到啊! 呸,不对, 因为要早起去打工!"
Mason 白了张大胖一眼说: "起不来是因为你天天熬夜,坐错车是因为两个原因: 1.没有check车牌 2.DD专车不止一辆"
大胖 一脸懵X 的问道 "绕了半天, 那这上错车和Spring创建Bean时的循环依赖又有什么关系呢 ?"
Mason 一脸这孩子没救了的表情回答道 "循环依赖的触发条件就是, 你上了别人的DD专车, 而你打DD专车, 判断是否循环依赖就需要 check车牌,如果要彻底根治循环依赖就必须让世界上的 DD专车 只有一辆. Spring 中的循环依赖也是同理!"
见微知著
我们暂不讨论 Spring 的循环依赖, 先看一道 LeetCode 题目 141. 环形链表
扩展: 在多线程环境下使用JDK1.7中的HashMap, 并发调用resize()时会出现环形链表,后再get()会导致CPU 100%, 那我们该如何去判断环形链表呢?
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是
-1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
那么 Spring 中是用那种方式发现 循环依赖的呢 ? (文章结尾揭晓答案)
// Definition for singly-linked list.
public class ListNode {
public int val;
public ListNode next;
public ListNode(int x) {
val = x;
}
}
Set判重
public boolean hasCycle_Set(ListNode head) {
// 如果入参链表过短则不存在环
if (head == null || head.next == null) {
return false;
}
HashSet<ListNode> set = new HashSet<>();
// 如果 遍历到最后任然没有发现环则不存在环
while (head.next != null){
// 将每一个遍历过的元素存入,之后判重
if (set.contains(head)){
return true;
}
set.add(head);
head = head.next;
}
return false;
}
快慢指针判重
public boolean hasCycle_QuickSlowPointer (ListNode head) {
// 如果入参链表过短则不存在环
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head;
// 如果 快指针遍历到最后仍然没有发现环则不存在环
while (fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
// 快指针每轮走两步 慢指针每轮走一步 如果有环快慢指针最终就会相遇
if (slow == fast){
return true;
}
}
return false;
}
新整了个活, 今后长期维护的一个LeetCode题解库,欢迎 Star
Spring 中常用的两种 Bean DI 方式的循环依赖示例
Spring DI (Dependency Injection 依赖注入) 是指 Bean 被动接受其他 Bean的依赖注入而不自己主动去找, 简而言之
Bean 不会从容器中查找它依赖的 Bean , 而是靠容器实例化 Bean 时由容器将它依赖的 Bean 注入, 此举与Java 类实例化流程相反.
构造器 DI 示例代码(基于Spring 5.1.6)
package org.springframework.context.annotationX.circular.constructor;
import org.springframework.stereotype.Component;
/**
* Spring Constructor DI 循环依赖 Bean1 Demo
*/
@Component
public class Bean1ConstructorBean2Demo {
private Bean2ConstructorBean1Demo bean2;
public Bean1ConstructorBean2Demo(Bean2ConstructorBean1Demo bean2DependBean1Demo) {
this.bean2 = bean2DependBean1Demo;
}
public void hello() {
bean2.hello();
}
}
package org.springframework.context.annotationX.circular.constructor;
import org.springframework.stereotype.Component;
/**
* Spring Constructor DI 循环依赖 Bean2 Demo
*/
@Component
public class Bean2ConstructorBean1Demo {
private Bean1ConstructorBean2Demo bean1;
public Bean2ConstructorBean1Demo(Bean1ConstructorBean2Demo bean1DependBean2Demo1) {
bean1 = bean1DependBean2Demo1;
}
public void hello() {
System.out.println("Run Circular Dependency Success");
}
}
注解自动装配 DI 示例代码
package org.springframework.context.annotationX.circular.autowired;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Spring @Autowired DI 循环依赖 Bean1 Demo
*/
@Component
public class Bean1AutowiredBean2Demo {
@Autowired
private Bean2AutowiredBean1Demo bean2;
public void hello() {
bean2.hello();
}
}
package org.springframework.context.annotationX.circular.autowired;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Spring @Autowired DI 循环依赖 Bean2 Demo
*/
@Component
public class Bean2AutowiredBean1Demo {
@Autowired
private Bean1AutowiredBean2Demo bean1;
public void hello(){
System.out.println("Run Circular Dependency Success");
}
}
两种 DI 方式的单元测试代码
package org.springframework.context;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotationX.circular.autowired.Bean1AutowiredBean2Demo;
import org.springframework.context.annotationX.circular.constructor.Bean1ConstructorBean2Demo;
/**
* Created by 以斗争求团结则团结存,以退让求团结则团结亡 !
*/
public class AnnotationCircularDependencyTestX {
@Test
public void diBeanByAutowired() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.annotationX.circular.autowired");
context.refresh();
Bean1AutowiredBean2Demo bean1 = (Bean1AutowiredBean2Demo) context.getBean("bean1AutowiredBean2Demo");
bean1.hello();
}
@Test
public void diBeanByConstructor () throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.annotationX.circular.constructor");
context.refresh();
Bean1ConstructorBean2Demo bean1 = (Bean1ConstructorBean2Demo) context.getBean("bean1ConstructorBean2Demo");
bean1.hello();
}
}
猜猜上面那种 DI 方式打印了 “Run Circular Dependency Success” 以及它解决循环依赖的方式 ?
答案: 注解自动装配 DI 示例代码 打印成功 而 构造器 DI 示例代码因为循环依赖运行失败 , 那这两种方式有什么区别呢 !
(构造器 DI 错误日志)
Unsatisfied dependency expressed through constructor parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name
'bean2ConstructorBean1Demo' defined in file
[D:\SpringFamily-SourceCodeStudy\Spring-Framework\spring-framework-5.1.6.REL
EASE\spring-context\out\test\classes\org\springframework\context\annotationX\circular\constructor\Bean2Const
ructorBean1Demo.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name
'bean1ConstructorBean2Demo': Requested bean is currently in creation: Is there an unresolvable circular
reference?
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
....
-
注解自动装配 DI 方式
-
优点:
-
基于三层缓存不会发生循环依赖
-
自描述清晰
-
-
缺点:
- 对构建单元测试不友好
-
-
构造器 DI 方式
- 优点:
- 代码结构明确,可读性高
- 构建单元测试友好
- 非IOC容器环境可使用new实例化该类的对象。
- 缺点:
- 会发生循环依赖
- 当注入参数较多时,代码臃肿。
- 优点:
对于循环依赖问题,Spring根据注入方式,采取不同的处理策略,如果依赖双方都是使用属性值注入或者Setter方法注入,则Spring可以自动解决循环依赖注入问题,Spring 程序可以成功启动;如果依赖双方是使用构造函数注入对方或者主Bean对象使用构造函数注入或循环注入的Bean都是原型模式,则Spring 无法解决循环依赖注入 ,Spring程序报循环依赖无法启动。
注解 DI 方式 的运行成功原因
注解 DI 方式与 构造器 DI 方式 最终要达到的目的相同, 但Spring 对它俩的实现却不太一样,
Spring-Context 在 AbstractApplicationContext.refresh()
方法完成 Bean 的关键生命周期 IOC, 实例化, DI 等,
DI 具体是 IOC 完成后调用 finishBeanFactoryInitialization()
方法, 具体方法逻辑如下
-
能触发依赖注入的条件有俩: 1. 第一次调用 getBean 方法时, 2. 懒加载被预实例化时, 此方法满足了其中第一条.
-
1.根据 beanDefinitionMap 依次判断 Bean 是否 Lazy, 是否 Prototype, 是否 Abstract 等等
-
2.接下来根据判断结果 填充构造方法来反射 Bean 的从而实例化. 所以在此之前必须推断Bean的构造方法.
-
3.反射实例化一个对象;注意我这里说的是对象、对象、对象;不是并不是一个完整的bean,因为 对象属性是没有注入,所以不是一个完整的bean;
-
4.Spring 处理 合并后的 BeanDefinition.
-
5.判断是否支持 循环依赖 如果支持则提前把 一个工厂存入
singletonFactories
Map<String, ObjectFactory<?>> -
6.进行属性注入
-
7.回调 Aware 接口, 生命周期回调方法, 是否需要代理
-
8.put 到 Spring容器
-
文章最后会带大家详细阅读上述源码.
成功原因:
// 是否需要提前曝光,用来解决循环依赖时使用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 这里是一个匿名内部类, 为了循环引用, 尽早持有对象的引用
// 解决循环依赖 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 判断 singletonObjects 不存在 beanName
if (!this.singletonObjects.containsKey(beanName)) {
// 放入 beanName -> beanFactory,到时在 getSingleton() 获取单例时,可直接获取创建对应 bean 的工厂,解决循环依赖
this.singletonFactories.put(beanName, singletonFactory);
// 从提前曝光的缓存中移除,之前在 getSingleton() 放入的
this.earlySingletonObjects.remove(beanName);
// 往注册缓存中添加 beanName
this.registeredSingletons.add(beanName);
}
}
}
先来看 earlySingletonExposure
这个变量: 从字面意思理解就是需要提前曝光的单例。
有以下三个判断条件:
mbd
是否是单例- 该容器是否允许循环依赖
- 判断该
bean
是否在创建中。
如果这三个条件都满足的话,就会执行 addSingletonFactory
操作。要想着,写的代码都有用处,所以接下来看下这个操作解决的什么问题和在哪里使用到吧
Bean1AutowiredBean2Demo
类中含有属性 Bean2AutowiredBean1Demo
,Bean2AutowiredBean1Demo
类中含有属性 Bean1AutowiredBean2Demo
,这两个类在初始化的时候经历了以下的步骤:
- 创建
Bean1AutowiredBean2Demo
,先记录对应的beanName
然后将Bean1AutowiredBean2Demo
的创建工厂 beanFactoryA 放入缓存中 - 对
Bean1AutowiredBean2Demo
的属性填充方法populateBean
,检查到依赖Bean2AutowiredBean1Demo
,缓存中没有Bean2AutowiredBean1Demo
的实例或者单例缓存,于是要去实例化Bean2AutowiredBean1Demo
。 - 开始实例化
Bean2AutowiredBean1Demo
,经历创建Bean2AutowiredBean1Demo
的过程,到了属性填充方法,检查到依赖了Bean1AutowiredBean2Demo
。 - 调用
getBean(Bean1AutowiredBean2Demo)
方法,在这个函数中,不是真正去实例化Bean1AutowiredBean2Demo
,而是先去检测缓存中是否有已经创建好的对应的bean
,或者已经创建好的beanFactory
- 检测到
beanFactoryA
已经创建好了,而是直接调用ObjectFactory
去创建Bean1AutowiredBean2Demo
为什么注解DI 可以拿到之前的缓存呢?
- 因为你已经通过空参实例化完成了
Bean1AutowiredBean2Demo
并存在beanFactoryA
中,Bean2AutowiredBean1Demo
再来拿的话就通过 getBean->getSingleton()
拿到beanFactoryA
后注入到属性中既可完成 Bean的初始化, 而这一步是在实例化之后, 而用构造器DI 的话,Bean1AutowiredBean2Demo
实例化时会发生循环依赖.
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从单例池 (一级缓存) 中直接拿 Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 一级缓存中没有 该Bean, 并且当前 BeanName 在正在创建的 Set 集合中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从三级缓存拿 Bean, 原因: 第一次其实是拿不到的, 因为现在只有 二级缓存中 存了一个 工厂对象, 所以成立向三级缓存添加
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
构造器 DI 方式 运行失败的原因
构造方法DI 抛出异常前调用堆栈信息
失败原因: 根据上述堆栈可以分析,
autowireConstructor()
试图通过构造方法反射bean1ConstructorBean2Demo
实例时它必须先实例化bean2ConstructorBean1Demo
然后依次循环, 走到getSingleton() ->
DefaultSingletonBeanRegistry.beforeSingletonCreation()
方法时就检测出异常, 那么为什么这种方式没有像 注解 DI 那样解决问题呢 ?
- 注解DI方式 与 构造器DI方式最大的区别在与
AbstractAutowireCapableBeanFactory.createBeanInstance()
中的实例化策略不太一样. 从各自定义SpringBean的源代码上看, 构造器DI方式 需要申明当前类的构造器以及依赖的类, 而 注解DI方式则不需要 (默认空参) - 构造器DI:
return autowireConstructor(beanName, mbd, ctors, args);
使用容器的自动装配特性, 调用匹配的构造方法进行实例化 - 注解DI:
return instantiateBean(beanName, mbd);
使用默认的无参构造方法进行实例化 - 如上图所示, 调用堆栈 在
createBeanInstance()
实例化方法中发生了循环引用, 并没有执行到populateBean()
进行依赖注入. 为什么会发生这一切?
在此之前建议阅读一下 Spring官方对循环依赖的文档
DI时 thorw BeanCurrentlyInCreationException 代码片段
// 构造方法DI getSingleton() 中 thorw BeanCurrentlyInCreationException
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 当前 Bean 不存在可排除的 inCreationCheckExclusions && 当前 Bean 之前已存在于 则 thorw singletonsCurrentlyInCreation 中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
}
构造方法DI thorw 的触发原因: 两次
beforeSingletonCreation()
同一个Bean, 因为如果是没有发生循环依赖的话接下来会执行afterSingletonCreation(beanName)
清除本轮singletonsCurrentlyInCreation.remove(beanName)
但在beforeSingletonCreation--> 递归 autowireConstructor() <--afterSingletonCreation
因此触发.
// 原型BeanDI doGetBean 中 thorw BeanCurrentlyInCreationException
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 如果之前创建过相同的原型Bean 则 thorw
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/** 创建原型模式 Bean 的实例对象*/
if (mbd.isPrototype()) {
// 原型模式 (Prototype) 每次都会创建一个新的对象
Object prototypeInstance = null;
try {
// 回调 beforePrototypeCreation() 方法, 默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
// 创建指定 Bean 的对象实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 回调 afterPrototypeCreation() 方法, 默认的功能是告诉 IOC 容器 不再创建指定 Bean 的原型对象
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
...
}
}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
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))));
}
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}
}
原型BeanDI thorw 的触发原因: 两次
beforePrototypeCreation()
同一个Bean, 因为如果是没有发生循环依赖的话接下来会执行afterPrototypeCreation(beanName)
清除本轮prototypesCurrentlyInCreation.remove()
但在beforePrototypeCreation--> 递归 doGetBean() <--afterPrototypeCreation
因此触发.
回溯几个有意思的问题
Spring是如何发现循环依赖的?
巧妙的用了LeetCode[141]中 Set 解法 把Bean 的加载顺序当作一个单向链表边存入边判重.
Spring的注解DI方式 是如何解决循环依赖的 ?
因为使用 注解DI 代码风格上是没有构造函数的, 在AbstractAutowireCapableBeanFactory.createBeanInstance()
走空参构造进行实例化, 所以不需要去像构造器DI 那样去实例化别的类, 然后在 populateBean()
中进行属性注入, 这时候已经完成实例化了要进行依赖注入了, 构造器DI方式就是在 实例化的时候翻车的呀, 具体怎么进行循环依赖的属性注入就靠 二 三级缓存咯.
-
一级缓存: singletonObjects 它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例Bean的地方, 也可以称之为 Spring 容器.
-
二级缓存: singletonFactories 映射创建Bean的原始工厂
-
三级缓存: earlySingletonObjects 映射Bean的早期引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance.
千言万语都在gif图里, 感谢作者vt 授权…
修复构造器 DI 引发的循环依赖的补丁有那几种 ?
- 在主构造DI 方法上加上 @Lazy, Spring会动态代理创建代理类来解决
- 在发生循环依赖的注入主类上加上 @Autowired, 并记得删除构造函数
- 实现 InitializingBean, ApplicationContextAware 接口, 在Spring 用 InitializingBean 时手动获取容器注入.
- 更多
Spring Bean 是如何被创建的 ?
在学习 Spring 时你可以把它比作一家 糖果工厂 , 糖果工厂里很多条夹心软糖生产线, 其中最赚钱的两条夹心软糖生产线, 分别是A生产线 与X生产线, A生产线生产软糖要必备一种叫@注解的糖浆原料, X 生产线则要必备另一种叫<!–Xml 的糖浆原料, 众所周知软糖生产有四大工艺 定位
-> 加载
-> 注册
->DI
在这点上它俩除了 定位
, 加载
不一样其他工艺则相同, 这两条生产线虽然工序,原料不同但生产的夹心软糖口感一致, 不过 A生产线软糖包装上选用了市面上 流行的透明塑料包装, 透着一股子干净简练, 而 X生产线 软糖包装则用的是白卡纸包裹的严严实实, 每次顾客拆包装都要费点工夫, X 生产线 是厂里的元老了, 诞生于 百糖争鸣的 Servlet 2.0 年代, 当年它的粉丝都是一水的棒小伙, 乖小妹, 现在爱吃它的还同一批人 但都变成了老头老太, 外加一批 软糖考古学者, A 生产线 崛起于 和平盛世的 Servlet 3.0 年代, 它紧跟时代潮流, 潮流里的后浪也紧跟着它, 无数青少年吃着它跨入不惑之年. 年轻人 ,你想听我讲讲这两条生产线的生产软糖的故事吗?
A 生产线 (AnnotationConfigApplicationContext) UML
X 生产线 (ClassPathXmlApplicationContext) UML
准备生产所需的原料
package org.springframework.context.softsweetsX;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.ZoneId;
@Component
public class SoftSweetsBean implements InitializingBean, ApplicationContextAware {
private String productionLineName;
private String dateManufacture;
public String getProductionLineName() {
return productionLineName;
}
public String getDateManufacture() {
return dateManufacture;
}
@Override
public void afterPropertiesSet() throws Exception {
this.dateManufacture = Instant.now().atZone(ZoneId.systemDefault()).toString();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.productionLineName = applicationContext.getDisplayName();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--SoftSweetsX.xml-->
<beans>
<bean id="softSweetsBean" class="org.springframework.context.softsweetsX.SoftSweetsBean"/>
</beans>
两种软糖的初体验
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SoftSweetsTest {
@Test
public void A_ProductLine() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.softsweetsX");
context.refresh();
SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
System.out.println("\n新鲜出炉的A软糖 ~~~ \n 生产线名称: " + bean.getProductionLineName() + "\n 生产日期: " + bean.getDateManufacture());
}
@Test
public void X_ProductLine() {
// test-resources
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("org/springframework/beans/factory/xml/SoftSweetsX.xml");
SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
System.out.println("\n新鲜出炉的X软糖 ~~~ \n 生产线名称: " + bean.getProductionLineName() + "\n 生产日期: " + bean.getDateManufacture());
}
}
控制台输出结果
新鲜出炉的X软糖 ~~~
生产线名称: org.springframework.context.support.ClassPathXmlApplicationContext@525b461a
生产日期: 2020-05-28T13:57:23.738+08:00[Asia/Shanghai]
新鲜出炉的A软糖 ~~~
生产线名称: org.springframework.context.annotation.AnnotationConfigApplicationContext@10db82ae
生产日期: 2020-05-28T13:57:24.784+08:00[Asia/Shanghai]
如果你对生产软糖感兴趣 来吧? -> SpringFamily-SourceCodeStudy
Bean 加载步骤
-
IOC (Inversion of Control 控制反转)
- 定位 (确定原料位置)
- 加载 (找到原料后提取为可注册 BeanDefinition)
- 注册 (将 BeanDefinition 校验后注册到 Map<String, BeanDefinition> beanDefinitionMap)
-
DI (Dependency Injection 依赖注入)
- 实例化 (反射 new 对象)ioc
- 依赖注入 (容器主动查找 bean 依赖)
IOC 控制反转
两条生产线的
定位
与加载
代码
// X 生产线
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 设置容器资源加载器
super(parent);
/* <定位/> 将配置的Bean信息为 Spring 封装的 Resource */
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建 XmlBeanDefinitionReader, 即创建 Bean 读取器
// <加载/> 并通过回调设置到容器中, 容器使用该读取器读取 Bean 配置资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 为 Bean 读取器设置 Spring 资源加载器
// AbstractXmlApplicationContext 的祖先父类 AbstractApplicationContext 继承 DefaultResourceLoader
// 因此容器本身也是一个资源加载器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
// 为Bean 读取器设置 SAX xml 解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 当Bean 读取器读取 Bean 定义 xml 资源文件时, 启用 xml 的校验机制
initBeanDefinitionReader(beanDefinitionReader);
// Bean 读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
// 按照 Spring 的Bean 语义要求将 Bean 配置信息解析并转换为容器内部数据结构
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
/* 得到 BeanDefinitionDocumentReader 来对 XML 格式的 BeanDefinition 进行解析*/
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获得容器中注册的 Bean 总数 (包含内置 bean)
int countBefore = getRegistry().getBeanDefinitionCount();
// 解析过程的入口, 这里使用了委派模式, BeanDefinitionDocumentReader 只是一个接口
/* <注册/> 具体的解析过程由实现类 DefaultBeanDefinitionDocumentReader 完成 */
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 统计解析的 Bean 数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
}
}
// ----------------------------------------------- 分割线 ---------------------------------------------------
// A 生产线
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
/* <定位/> */
this.scanner.scan(basePackages);
}
}
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
public int scan(String... basePackages) {
// 获得容器中注册的 Bean 总数 (包含内置 bean)
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
// 统计解析的 Bean 数量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
/* <加载/> */
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
/* <注册/> */
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}
上述代码 表示 两条生产线
定位
载入
是不同的, 但从 UML 类图看 它俩 都继承了AbstractApplicationContext
所以注册
DI
是相同的
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
// 存储注册信息 BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 校验解析的 beanDefinition
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// 注册的过程中需要线程同步, 以保证数据的一致性
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 检查是否已经注册过同名的 beanDefinition
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置所有已经注册过的 beanDefinition 缓存
resetBeanDefinition(beanName);
}
}
}
总揽全局, 可以看到我们讲的
IOC
与DI
只是众多 Spring 生命周期中的一部分.
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 调用容器准备的刷新方法, 获取容器的当前时间, 同时给容器设置同步标识
prepareRefresh();
// 2. <X 生产线 IOC/> 告诉子类启动 refreshBeanFactory()方法, Bean定义资源文件的载入从子类的 refreshBeanFactory() 方法启动
// 继承了 AbstractRefreshableApplicationContext 的容器子类可以调用, 从 UML 图上看 X 生产线可以,A 生产线不行
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 为 BeanFactory 配置容器特性, 例如类加载器, 事件处理器等
prepareBeanFactory(beanFactory);
try {
// 4. 为容器的某些子类指定的特殊的 Post 事件处理器
postProcessBeanFactory(beanFactory);
// 5. <A 生产线 IOC/> 调用所有注册的 BeanFactoryPostProcessor 的 Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 为 BeanFactory 注册 Post 事件处理器
// BeanPostProcessor 是Bean 后置处理器, 用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
// 7. 初始化信息源, 和国际化相关
initMessageSource();
// 8. 初始化容器事件传播器
initApplicationEventMulticaster();
// 9. 调用子类的某些特殊的Bean的初始化方法
onRefresh();
// 10. 为事件传播器注册事件监听器
registerListeners();
// 11. <DI/> 初始化所有剩余的单例模式Bean (non-lazy-init)
finishBeanFactoryInitialization(beanFactory);
// 12. 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 13. 销毁已经创建的单例Bean,以避免挂起资源。
destroyBeans();
// 14. 取消刷新操作, 重置容器的同步标识
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// 15. 重设公共缓存, 可能再也不需要单例bean的元数据了……
resetCommonCaches();
}
}
}
}
DI 依赖注入
循环依赖就发生在 DI 依赖注入这一步. 接下来我们详细探讨一下 它的原理. 看千遍不如手动搞一遍, 不然只是别人的知识,
依赖注入触发规则
- 用户第一次调用 getBean 方法时, IOC 容器触发依赖注入
- Bean 设置为 懒加载, 在需要预实例化 Bean 时触发依赖注入
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
// 11. <DI/> 初始化所有剩余的单例模式Bean (non-lazy-init)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
beanFactory.preInstantiateSingletons();
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 触发所有非惰性单例bean的实例化…
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
...
}
else {
// <实例化/> 第一次调用 getBean 方法时, IOC 容器触发当前 Bean的依赖注入与实例化
getBean(beanName);
}
}
}
...
}
}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@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 名称, 剥离指定名称中对容器的相关依赖
// 如果指定的是别名, 将别名转换为 规范的 Bean 名称
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中读取是否已经有被创建过的单例模式的 Bean
// 对于单例模式的Bean 整个 IOC 容器中只创建一次, 不需要重复创建
Object sharedInstance = getSingleton(beanName);
// IOC 容器创建单例模式的 Bean 示例对象
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
// 如果在容器中已有指定名称的单例模式 Bean 被创建, 直接返回已经创建的 Bean
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 + "'");
}
}
// 注意: FactoryBean 是创建对象的工厂 Bean, BeanFactory 是管理 Bean 的工厂
// 获取给定 Bean 的实例对象, 主要完成 FactoryBean 的相关处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 缓存中没有正在创建的 单例模式的 Bean
// 缓存中已有原型模式的 Bean
// 但是由于循环依赖导致实例化对象失败
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 对 IOC 容器中是否存在指定名称的 BeanDefinition 进行检查
// 首先检查是否能对当前的 BeanFactory 中获取所需要的 Bean,
// 如果不能则委托当前容器的父容器去查找, 如果还是找不到则沿着容器的继承体系向父容器查找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 解析指定 Bean 名称的原始名称
String nameToLookup = originalBeanName(name);
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);
}
}
// 创建的 Bean 是否需要进行类型验证, 一般不需要
if (!typeCheckOnly) {
// 向容器标记指定的 Bean 已经被创建
markBeanAsCreated(beanName);
}
try {
// 根据指定 Bean 名称获取其父级 Bean 定义
// 主要解决 Bean 继承子类和父类公共属性问题
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 获取当前 Bean 所有依赖 Bean 的名称
String[] dependsOn = mbd.getDependsOn();
/** 如果当前 Bean 有 @DependsOn 依赖的 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 + "'");
}
// 把被依赖 Bean 注册给当前依赖的 Bean
registerDependentBean(dep, beanName);
try {
// 递归调用 getBean()方法, 获取给当前依赖 Bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/** 创建单例模式的 Bean 的实例对象*/
if (mbd.isSingleton()) {
// 这里使用了一个匿名的内部类创建 Bean 实例对象, 并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
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;
}
});
// 获取给定的 Bean 实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
/** 创建原型模式 Bean 的实例对象*/
else if (mbd.isPrototype()) {
// 原型模式 (Prototype) 每次都会创建一个新的对象
Object prototypeInstance = null;
try {
// 回调 beforePrototypeCreation() 方法, 默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
// 创建指定 Bean 的对象实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 回调 afterPrototypeCreation() 方法, 默认的功能是告诉 IOC 容器 不再创建指定 Bean 的原型对象
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
/** 创建 Web Bean 的实例对象, 比如 request , session, application 等生命周期*/
else {
// 要创建的 Bean 既不是单例模式的, 也不是原型模式的, 则根据 Bean 定义资源中
// 配置的生命周期范围, 选择实例化 Bean 的合适方法, 这种方式在多用于 Web 应用程序中
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
// 如果Bean 定义资源中没有配置生命周期范围, 则Bean定义不合法
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 的实例对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
....
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
...
return (T) bean;
}
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 封装被创建的 Bean 对象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// 获取实例化对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 调用 PostProcessor 后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
...
}
mbd.postProcessed = true;
}
}
// 向容器中 缓存单例模式的 Bean 对象, 以防止循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 这里是一个匿名内部类, 为了循环引用, 尽早持有对象的引用
// 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Bean 对象的初始化, 依赖注入在此触发
Object exposedObject = bean;
try {
// 将 Bean 实例对象封装, 并且将 Bean 定义中配置的属性值赋给实例对象
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 获取指定名称的已注册的单例模式 Bean 对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 根据名称获取 的已注册的 Bean 和正在实例化的 Bean 是同一个
if (exposedObject == bean) {
// 当前实例化的 Bean 初始化完成
exposedObject = earlySingletonReference;
}
// 当前 Bean 依赖其他 Bean, 并且当发生循环引用时不允许创建新的实例对象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
// 获取当前 Bean 所依赖的其他 Bean
for (String dependentBean : dependentBeans) {
// 对依赖 Bean 进行类型检查
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
...
}
}
}
}
// 注册完成依赖注入的 Bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
后话
Mason 能看懂源码,主要有两方面在起作用,
一方面是因为水滴石穿的不懈努力,客观上起了作用,
一方面是因为 Mason 通过读毛选掌握了克服困难的方法论, 主观上起了作用,
推荐大家参加 毛三公的B站活动 #我在读毛选#
共同学习,写下你的评论
评论加载中...
作者其他优质文章