Skip to content

Commit 35a7c4a

Browse files
authored
feat(spring): add circular dependency article (doocs#127)
1 parent 8d37a71 commit 35a7c4a

3 files changed

Lines changed: 269 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- [BeanFactoryPostProcessor](/docs/Spring/IoC/BeanFactoryPostProcessor.md)
2828
- [BeanPostProcessor](/docs/Spring/IoC/BeanPostProcessor.md)
2929
- [Spring BeanFactory 源码解析](/docs/Spring/clazz/Spring-beanFactory.md)
30+
- [循环依赖](/docs/Spring/IoC/循环依赖.md)
3031

3132
### AOP
3233

docs/Spring/IoC/循环依赖.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# 循环依赖
2+
3+
一个对象依赖对象闭环到自己
4+
5+
> A -> B -> .... ->A
6+
7+
tip:
8+
9+
> 不涉及代理对象问题
10+
11+
解决方法:当一个对象已经实例化完毕了,还未初始化的时候,将它注入到它所依赖的已经实例好的对象(提前暴露对象),使得它所依赖的对象是个完整对象(实例化+初始化),然后再将这个完整对象注入给它。
12+
13+
## 简单工程(Spring-version-5.3.18)
14+
15+
我们就用下面两个类进行实践,多个类间依赖也是如此。
16+
17+
A 类
18+
19+
```java
20+
package cn.demo1;
21+
22+
import lombok.Getter;
23+
import lombok.Setter;
24+
25+
@Setter
26+
@Getter
27+
public class A {
28+
private B b;
29+
}
30+
```
31+
32+
B 类
33+
34+
```java
35+
package cn.demo1;
36+
37+
import lombok.Getter;
38+
import lombok.Setter;
39+
40+
@Setter
41+
@Getter
42+
public class B {
43+
private A a;
44+
}
45+
```
46+
47+
配置文件 test1.xml
48+
49+
```xml
50+
<?xml version="1.0" encoding="UTF-8"?>
51+
<beans xmlns="http://www.springframework.org/schema/beans"
52+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
53+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
54+
<bean id="a" class="cn.demo1.A">
55+
<property name="b" ref="b"/>
56+
</bean>
57+
58+
<bean id="b" class="cn.demo1.B">
59+
<property name="a" ref="a"/>
60+
</bean>
61+
</beans>
62+
```
63+
64+
DefaultSingletonBeanRegistry 类中的几个特别重要的属性
65+
66+
```java
67+
// 一级缓存 存放完整Bean对象(实例化+初始化)
68+
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
69+
70+
// 三级缓存 存放一个lambda表达式
71+
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
72+
73+
// 二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
74+
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
75+
```
76+
77+
> 循环依赖问题应该是出现属性填充的时候
78+
79+
doCreateBean 这个方法
80+
81+
> 可以参照 [createBeanInstance](/docs/Spring/clazz/Spring-beanFactory.md#createbeaninstance) 查看 Spring 是怎么实例化的
82+
83+
```java
84+
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
85+
throws BeanCreationException {
86+
// bean的包装类
87+
BeanWrapper instanceWrapper = null;
88+
if (mbd.isSingleton()) {
89+
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
90+
}
91+
if (instanceWrapper == null) {
92+
// 就只是bean的实例化
93+
instanceWrapper = createBeanInstance(beanName, mbd, args);
94+
}
95+
Object bean = instanceWrapper.getWrappedInstance();
96+
Class<?> beanType = instanceWrapper.getWrappedClass();
97+
if (beanType != NullBean.class) {
98+
mbd.resolvedTargetType = beanType;
99+
}
100+
101+
// 一般为true
102+
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
103+
// ....省略部分
104+
if (earlySingletonExposure) {
105+
106+
// 这里是将一段lambda放入三级缓存中,可以看见bean填充属性之前会将三级缓存创建好,它传入了一个还未初始化的bean
107+
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
108+
}
109+
Object exposedObject = bean;
110+
try {
111+
populateBean(beanName, mbd, instanceWrapper);
112+
exposedObject = initializeBean(beanName, exposedObject, mbd);
113+
}
114+
// ..........省略部分
115+
return exposedObject;
116+
}
117+
```
118+
119+
addSingletonFactory
120+
121+
```java
122+
// 其中singletonFactory是一个lambda表达式
123+
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
124+
Assert.notNull(singletonFactory, "Singleton factory must not be null");
125+
synchronized (this.singletonObjects) {
126+
// 如果我们一级缓存中不存在这个叫beanName的bean
127+
if (!this.singletonObjects.containsKey(beanName)) {
128+
// 放入三级缓存中
129+
this.singletonFactories.put(beanName, singletonFactory);
130+
// 把二级缓存中叫beanName的半成品bean删除
131+
this.earlySingletonObjects.remove(beanName);
132+
// 标记当前注册的bean
133+
this.registeredSingletons.add(beanName);
134+
}
135+
}
136+
}
137+
```
138+
139+
lambda 所执行的方法
140+
141+
```java
142+
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
143+
Object exposedObject = bean;
144+
// 普通bean是进不来的
145+
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
146+
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
147+
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
148+
}
149+
}
150+
// 直接返回传进来的bean,返回的是一个还未初始化的bean,是提前暴露的
151+
return exposedObject;
152+
}
153+
```
154+
155+
populateBean 中有调用了 applyPropertyValues 这个方法具体详情请点击这里 [applyProertyValues](/docs/Spring/clazz/Spring-beanFactory.md#applypropertyvalues)
156+
157+
```java
158+
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
159+
160+
// Create a deep copy, resolving any references for values.
161+
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
162+
boolean resolveNecessary = false;
163+
for (PropertyValue pv : original) {
164+
if (pv.isConverted()) {
165+
deepCopy.add(pv);
166+
}
167+
else {
168+
// 属性名字
169+
String propertyName = pv.getName();
170+
//当你引用另一个bean的时候,会把它封装成RuntimeBeanReference这个对象,便于操作
171+
Object originalValue = pv.getValue();
172+
// 这里是解析的工作,也就是会产生循环依赖产生的地方
173+
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
174+
// 省略....
175+
}
176+
}
177+
```
178+
179+
applyPropertyValues 中有个重要的方法调用,省略无关代码
180+
181+
```java
182+
// 我们当前需要要的就是
183+
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
184+
// 当前bean的属性值的类型正是这个
185+
if (value instanceof RuntimeBeanReference) {
186+
RuntimeBeanReference ref = (RuntimeBeanReference) value;
187+
return resolveReference(argName, ref);
188+
}
189+
// 省略...
190+
}
191+
```
192+
193+
resolveReferance 中有一段代码
194+
195+
```java
196+
// 这个方法会调用getBean
197+
@Nullable
198+
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
199+
// 省略...
200+
201+
// 上面一般进不去,直接看这个重点
202+
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
203+
// 获取所依赖的bean
204+
bean = this.beanFactory.getBean(resolvedName);
205+
206+
// 省略...
207+
208+
}
209+
```
210+
211+
getBean 从而到这个 doGetBean 方法,其他代码不多说,最主要是下面这个
212+
213+
其中有一段代码,首先它会尝试从缓存中获取到 bean,如果获取不到就创建这个 bean
214+
215+
```java
216+
Object sharedInstance = getSingleton(beanName);
217+
```
218+
219+
> 获取缓存 bean 的顺序是,先从一级缓存中取,若不存在,从二级缓存中取,若还是不存在,则从三级缓存中取
220+
221+
```java
222+
@Nullable
223+
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
224+
// 一级缓存中是否存在
225+
Object singletonObject = this.singletonObjects.get(beanName);
226+
// 如果想要获取的bean正在创建中且无一级缓存
227+
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
228+
// 尝试二级缓存
229+
singletonObject = this.earlySingletonObjects.get(beanName);
230+
if (singletonObject == null && allowEarlyReference) {
231+
synchronized (this.singletonObjects) {
232+
singletonObject = this.singletonObjects.get(beanName);
233+
if (singletonObject == null) {
234+
// 获取二级缓存
235+
singletonObject = this.earlySingletonObjects.get(beanName);
236+
if (singletonObject == null) {
237+
// 获取三级缓存
238+
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
239+
if (singletonFactory != null) {
240+
// 调用三级缓存,这个地方就会调用我们的lambda表达式了
241+
/**
242+
*() -> getEarlyBeanReference(beanName, mbd, bean)
243+
*这里就是我们解决办法的地方,因为所有普通的bean会首先提前进行三级缓存
244+
*所以这里会获取到还未初始化的bean,从而赋值到所依赖当前singletonObject对象的bean
245+
*/
246+
singletonObject = singletonFactory.getObject();
247+
// 放入二级缓存中
248+
this.earlySingletonObjects.put(beanName, singletonObject);
249+
// 三级缓存中移除当前beanName的lambda表达式
250+
this.singletonFactories.remove(beanName);
251+
}
252+
}
253+
}
254+
}
255+
}
256+
}
257+
// 完整对象或者还未初始化的对象
258+
return singletonObject;
259+
}
260+
```
261+
262+
最后经历这个就获取到一个半成品对象所依赖的一个完整对象,然后再将完整对象注入半成品对象中。
263+
264+
## 历程
265+
266+
> 该历程仅代表当前这个项目工程
267+
268+
![image](/images/spring/循环依赖.png)

images/spring/循环依赖.png

58.8 KB
Loading

0 commit comments

Comments
 (0)