You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
source-code-hunter/docs/Spring/IoC/循环依赖.md

269 lines
9.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 循环依赖
一个对象依赖对象闭环到自己
> A -> B -> .... ->A
tip:
> 不涉及代理对象问题
解决方法:当一个对象已经实例化完毕了,还未初始化的时候,将它注入到它所依赖的已经实例好的对象(提前暴露对象),使得它所依赖的对象是个完整对象(实例化+初始化),然后再将这个完整对象注入给它。
## 简单工程Spring-version-5.3.18)
我们就用下面两个类进行实践,多个类间依赖也是如此。
A 类
```java
package cn.demo1;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class A {
private B b;
}
```
B 类
```java
package cn.demo1;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class B {
private A a;
}
```
配置文件 test1.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="cn.demo1.A">
<property name="b" ref="b"/>
</bean>
<bean id="b" class="cn.demo1.B">
<property name="a" ref="a"/>
</bean>
</beans>
```
DefaultSingletonBeanRegistry 类中的几个特别重要的属性
```java
// 一级缓存 存放完整Bean对象(实例化+初始化)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 三级缓存 存放一个lambda表达式
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
```
> 循环依赖问题应该是出现属性填充的时候
doCreateBean 这个方法
> 可以参照 [createBeanInstance](/docs/Spring/clazz/Spring-beanFactory.md#createbeaninstance) 查看 Spring 是怎么实例化的
```java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// bean的包装类
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 就只是bean的实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 一般为true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
// ....省略部分
if (earlySingletonExposure) {
// 这里是将一段lambda放入三级缓存中可以看见bean填充属性之前会将三级缓存创建好它传入了一个还未初始化的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// ..........省略部分
return exposedObject;
}
```
addSingletonFactory
```java
// 其中singletonFactory是一个lambda表达式
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 如果我们一级缓存中不存在这个叫beanName的bean
if (!this.singletonObjects.containsKey(beanName)) {
// 放入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
// 把二级缓存中叫beanName的半成品bean删除
this.earlySingletonObjects.remove(beanName);
// 标记当前注册的bean
this.registeredSingletons.add(beanName);
}
}
}
```
lambda 所执行的方法
```java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 普通bean是进不来的
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
// 直接返回传进来的bean返回的是一个还未初始化的bean是提前暴露的
return exposedObject;
}
```
populateBean 中有调用了 applyPropertyValues 这个方法具体详情请点击这里 [applyProertyValues](/docs/Spring/clazz/Spring-beanFactory.md#applypropertyvalues)
```java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
// 属性名字
String propertyName = pv.getName();
//当你引用另一个bean的时候会把它封装成RuntimeBeanReference这个对象便于操作
Object originalValue = pv.getValue();
// 这里是解析的工作,也就是会产生循环依赖产生的地方
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 省略....
}
}
```
applyPropertyValues 中有个重要的方法调用,省略无关代码
```java
// 我们当前需要要的就是
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// 当前bean的属性值的类型正是这个
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
// 省略...
}
```
resolveReferance 中有一段代码
```java
// 这个方法会调用getBean
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
// 省略...
// 上面一般进不去,直接看这个重点
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
// 获取所依赖的bean
bean = this.beanFactory.getBean(resolvedName);
// 省略...
}
```
getBean 从而到这个 doGetBean 方法,其他代码不多说,最主要是下面这个
其中有一段代码,首先它会尝试从缓存中获取到 bean如果获取不到就创建这个 bean
```java
Object sharedInstance = getSingleton(beanName);
```
> 获取缓存 bean 的顺序是,先从一级缓存中取,若不存在,从二级缓存中取,若还是不存在,则从三级缓存中取
```java
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存中是否存在
Object singletonObject = this.singletonObjects.get(beanName);
// 如果想要获取的bean正在创建中且无一级缓存
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 尝试二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 获取二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 获取三级缓存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用三级缓存这个地方就会调用我们的lambda表达式了
/**
*() -> getEarlyBeanReference(beanName, mbd, bean)
*这里就是我们解决办法的地方因为所有普通的bean会首先提前进行三级缓存
*所以这里会获取到还未初始化的bean从而赋值到所依赖当前singletonObject对象的bean
*/
singletonObject = singletonFactory.getObject();
// 放入二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 三级缓存中移除当前beanName的lambda表达式
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 完整对象或者还未初始化的对象
return singletonObject;
}
```
最后经历这个就获取到一个半成品对象所依赖的一个完整对象,然后再将完整对象注入半成品对象中。
## 历程
> 该历程仅代表当前这个项目工程
![image](/images/spring/循环依赖.png)