Spring Framework之加载机制的循环依赖单例Bean加载(三)

一、前言

声明:这个加载只适用循环依赖普通单例Bean加载流程,其它的bean流程只稍微有些差异

前文说明普通单例Bean的加载(忽略掉循环依赖、扩展、接口等),循环依赖也无异,通过下面3点我们讲了解简单的Spring加载:
1.Spring Framework中的循环依赖理论
2.游走循环依赖普通单列Bean加载源码
3、循环依赖最终图解

二、Spring Framework中的循环依赖理论

Bean的内部结构图
avatar
循环依赖
在Java层面

一个对象依赖另一个对象,只需要将Bean1对象地址赋给Bean2对象变量,Bean2对象地址赋给Bean1对象变量,以此达到对象间的循环依赖

在Spring framework层面

情况一(构造依赖):

Bean1未构建成功,立即构建Bean2,Bean2也未构建成功,立即构建Bean1,陷入循环,导致无法构建成功

Spring framework会抛出BeanCurrentlyInCreationException异常,Spring framework无法解决构造依赖

情况二(属性依赖):

Bean1构建时,会先将beanName放入当前创建的单列集中,并效验当前beanName是否存在单例工厂,使用构造函数完成构建,并添加到单例工厂,填充属性时,发现依赖Bean2,解决Bean2依赖时产生Bean1构建中断;

Bean2构建时,会先将beanName放入当前创建的单列集中,并效验当前beanName是否存在单例工厂,使用构造函数完成构建,并添加到单例工厂,填充属性时,发现依赖Bean1,解决Bean1依赖时产生Bean2构建中断;

Bean1构建时,发现当前beanName存在创建的单列集中,并且存在当前beanName的单例工厂,直接获取Bean并返回;

回到Bean2进行注入,回到Bean1进行注入

三、游走循环依赖普通单列Bean加载源码

属性依赖对象代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Bean1
public class SystemPrint {
@Autowired
SystemWrite systemWrite;
}

//Bean2
public class SystemWrite {
@Autowired
SystemPrint systemPrint;
}

//junit测试
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册一个SystemPrint bean 、SystemWrite bean
context.register(SystemPrint.class, SystemWrite.class);
// 刷新应用上下文
context.refresh();⬅️
// 获取IOC容器bean对象
Object bean = context.getBean(SystemPrint.class);
// 打印对象
log.info("{}",bean);
}

上下文刷新

具体参照前文Spring Framework之加载机制的单例Bean加载,本次获取的bean为SystemPrint对象,这里通过流程图来简略阐述上章流程

avatar
AbstractAutowireCapableBeanFactory

本章属性依赖重点类

avatar
avatar
AutowiredAnnotationBeanPostProcessor
avatar
InjectionMetadata
avatar
AutowiredFieldElement
avatar
DefaultListableBeanFactory
avatar
avatar
DependencyDescriptor
avatar

本次获取的是SystemWrite对象,重回流程图,AbstractBeanFactory.getBean(“systemWrite”);最终走先上图DependencyDescriptor,获取SystemPrint对象,重回流程图,AbstractBeanFactory.getBean(“systemPrint”);直到AbstractBeanFactory.doGetBean()方法

AbstractBeanFactory
avatar
DefaultSingletonBeanRegistry
avatar
avatar
程序输出

1
[Test worker] INFO SpringFrameworkTest - bean.SystemPrint@2fc749df

构造依赖对象代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Bean1
public class SystemPrint {
SystemWrite systemWrite;

public SystemPrint(SystemWrite systemWrite) {
this.systemWrite = systemWrite;
}
}

//Bean2
public class SystemWrite {
@Autowired
SystemPrint systemPrint;
}

//junit测试
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册一个SystemPrint bean 、SystemWrite bean
context.register(SystemPrint.class, SystemWrite.class);
// 刷新应用上下文
context.refresh();
// 获取IOC容器bean对象
Object bean = context.getBean(SystemPrint.class);
// 打印对象
log.info("{}",bean);
}

流程和属性一样,主要是实例化类的区别,直接定位AbstractAutowireCapableBeanFactory.doCreateBean()方法

AbstractAutowireCapableBeanFactory
avatar
avatar
avatar
ConstructorResolver

autowireConstructor()方法中定位

avatar

createArgumentArray()方法中定位

avatar
avatar

流程和 “ 构造依赖对象代码 ” 中 DefaultListableBeanFactory.resolveDependency()方法一直,急切获取属性SystemWrite对象,重回流程图,AbstractBeanFactory.getBean(“systemWrite”);最终走先上图DependencyDescriptor,获取SystemPrint对象,重回流程图,AbstractBeanFactory.getBean(“systemPrint”);直到DefaultSingletonBeanRegistry.getSingleton()方法

DefaultSingletonBeanRegistry
avatar
AbstractBeanFactory

doGetBean()方法中定位

avatar
DefaultSingletonBeanRegistry
avatar
avatar

经过一系列的抛出,最终定位ConstructorResolver.createArgumentArray()方法,抛出不满意的依赖异常,也就是循环依赖异常

ConstructorResolver
avatar

四、循环依赖最终图解

avatar

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信