Update 循环依赖.md

pull/127/head
Yang Libin 3 years ago committed by GitHub
parent 69770519cb
commit c0e37202a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,8 +1,8 @@
## 循环依赖
# 循环依赖
一个对象依赖对象闭环到自己
>A -> B -> .... ->A
> A -> B -> .... ->A
tip:
@ -10,13 +10,11 @@ tip:
解决方法:当一个对象已经实例化完毕了,还未初始化的时候,将它注入到它所依赖的已经实例好的对象(提前暴露对象),使得它所依赖的对象是个完整对象(实例化+初始化),然后再将这个完整对象注入给它。
<hr/>
### 简单工程Spring-version-5.3.18)
## 简单工程Spring-version-5.3.18)
我们就用下面两个类进行实践,多个类间依赖也是如此。
A类
A
```java
package cn.demo1;
@ -31,7 +29,7 @@ public class A {
}
```
B类
B
```java
package cn.demo1;
@ -46,7 +44,7 @@ public class B {
}
```
配置文件test1.xml
配置文件 test1.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
@ -63,24 +61,24 @@ public class B {
</beans>
```
DefaultSingletonBeanRegistry类中的几个特别重要的属性
DefaultSingletonBeanRegistry 类中的几个特别重要的属性
```java
//一级缓存 存放完整Bean对象(实例化+初始化)
// 一级缓存 存放完整Bean对象(实例化+初始化)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//三级缓存 存放一个lambda表达式
// 三级缓存 存放一个lambda表达式
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
// 二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
```
> 循环依赖问题应该是出现属性填充的时候
doCreateBean这个方法
doCreateBean 这个方法
> 可以参照[createBeanInstance](https://github.com/yang520-bye/source-code-hunter/blob/main/docs/Spring/clazz/Spring-beanFactory.md#createbeaninstance)查看Spring是怎么实例化的
> 可以参照 [createBeanInstance](/docs/Spring/clazz/Spring-beanFactory.md#createbeaninstance) 查看 Spring 是怎么实例化的
```java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
@ -91,7 +89,7 @@ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//就只是bean的实例化
// 就只是bean的实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
@ -99,13 +97,13 @@ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//一般为true
// 一般为true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
//....省略部分
// ....省略部分
if (earlySingletonExposure) {
//这里是将一段lambda放入三级缓存中可以看见bean填充属性之前会将三级缓存创建好它传入了一个还未初始化的bean
// 这里是将一段lambda放入三级缓存中可以看见bean填充属性之前会将三级缓存创建好它传入了一个还未初始化的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
@ -121,40 +119,40 @@ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable
addSingletonFactory
```java
//其中singletonFactory是一个lambda表达式
// 其中singletonFactory是一个lambda表达式
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
//如果我们一级缓存中不存在这个叫beanName的bean
// 如果我们一级缓存中不存在这个叫beanName的bean
if (!this.singletonObjects.containsKey(beanName)) {
//放入三级缓存中
// 放入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
//把二级缓存中叫beanName的半成品bean删除
// 把二级缓存中叫beanName的半成品bean删除
this.earlySingletonObjects.remove(beanName);
//标记当前注册的bean
// 标记当前注册的bean
this.registeredSingletons.add(beanName);
}
}
}
```
lambda所执行的方法
lambda 所执行的方法
```java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//普通bean是进不来的
// 普通bean是进不来的
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
//直接返回传进来的bean返回的是一个还未初始化的bean是提前暴露的
// 直接返回传进来的bean返回的是一个还未初始化的bean是提前暴露的
return exposedObject;
}
```
populateBean中有调用了applyPropertyValues这个方法具体详情请点击这里[applyProertyValues](https://github.com/doocs/source-code-hunter/blob/main/docs/Spring/clazz/Spring-beanFactory.md#applypropertyvalues)
populateBean 中有调用了 applyPropertyValues 这个方法具体详情请点击这里 [applyProertyValues](/docs/Spring/clazz/Spring-beanFactory.md#applypropertyvalues)
```java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
@ -167,88 +165,88 @@ protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrap
deepCopy.add(pv);
}
else {
//属性名字
// 属性名字
String propertyName = pv.getName();
//当你引用另一个bean的时候会把它封装成RuntimeBeanReference这个对象便于操作
Object originalValue = pv.getValue();
//这里是解析的工作,也就是会产生循环依赖产生的地方
// 这里是解析的工作,也就是会产生循环依赖产生的地方
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//省略....
// 省略....
}
}
```
applyPropertyValues中有个重要的方法调用省略无关代码
applyPropertyValues 中有个重要的方法调用,省略无关代码
```java
//我们当前需要要的就是
// 我们当前需要要的就是
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
//当前bean的属性值的类型正是这个
// 当前bean的属性值的类型正是这个
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
//省略...
// 省略...
}
```
resolveReferance中有一段代码
resolveReferance 中有一段代码
```java
//这个方法会调用getBean
// 这个方法会调用getBean
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
//省略...
//上面一般进不去,直接看这个重点
// 省略...
// 上面一般进不去,直接看这个重点
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
//获取所依赖的bean
// 获取所依赖的bean
bean = this.beanFactory.getBean(resolvedName);
//省略...
// 省略...
}
```
getBean从而到这个doGetBean方法其他代码不多说最主要是下面这个
getBean 从而到这个 doGetBean 方法,其他代码不多说,最主要是下面这个
其中有一段代码首先它会尝试从缓存中获取到bean如果获取不到就创建这个bean
其中有一段代码,首先它会尝试从缓存中获取到 bean如果获取不到就创建这个 bean
```java
Object sharedInstance = getSingleton(beanName);
```
> 获取缓存bean的顺序是先从一级缓存中取若不存在从二级缓存中取若还是不存在则从三级缓存中取
> 获取缓存 bean 的顺序是,先从一级缓存中取,若不存在,从二级缓存中取,若还是不存在,则从三级缓存中取
```java
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//一级缓存中是否存在
// 一级缓存中是否存在
Object singletonObject = this.singletonObjects.get(beanName);
//如果想要获取的bean正在创建中且无一级缓存
// 如果想要获取的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表达式了
// 调用三级缓存这个地方就会调用我们的lambda表达式了
/**
*() -> getEarlyBeanReference(beanName, mbd, bean)
*这里就是我们解决办法的地方因为所有普通的bean会首先提前进行三级缓存
*所以这里会获取到还未初始化的bean从而赋值到所依赖当前singletonObject对象的bean
*/
singletonObject = singletonFactory.getObject();
//放入二级缓存中
// 放入二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
//三级缓存中移除当前beanName的lambda表达式
// 三级缓存中移除当前beanName的lambda表达式
this.singletonFactories.remove(beanName);
}
}
@ -256,18 +254,15 @@ protected Object getSingleton(String beanName, boolean allowEarlyReference) {
}
}
}
//完整对象或者还未初始化的对象
// 完整对象或者还未初始化的对象
return singletonObject;
}
```
最后经历这个就获取到一个半成品对象所依赖的一个完整对象,然后再将完整对象注入半成品对象中。
<hr/>
### 历程
## 历程
Tip
> 该历程仅代表当前这个项目工程
>该历程仅代表当前这个项目工程
<img src="https://github.com/yang520-bye/source-code-hunter/blob/main/images/spring/%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96.png"/>
![image](/images/spring/循环依赖.png)

Loading…
Cancel
Save