From f89a766eda5e38b496e978f87585490019dfa18f Mon Sep 17 00:00:00 2001
From: qhling <78717426+yang520-bye@users.noreply.github.com>
Date: Fri, 10 Jun 2022 17:13:40 +0800
Subject: [PATCH] =?UTF-8?q?Create=20=E5=BE=AA=E7=8E=AF=E4=BE=9D=E8=B5=96.m?=
=?UTF-8?q?d?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/Spring/IoC/循环依赖.md | 273 ++++++++++++++++++++++++++++++++
1 file changed, 273 insertions(+)
create mode 100644 docs/Spring/IoC/循环依赖.md
diff --git a/docs/Spring/IoC/循环依赖.md b/docs/Spring/IoC/循环依赖.md
new file mode 100644
index 0000000..9a68d75
--- /dev/null
+++ b/docs/Spring/IoC/循环依赖.md
@@ -0,0 +1,273 @@
+## 循环依赖
+
+一个对象依赖对象闭环到自己
+
+>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
+
+
+
+
+
+
+
+
+
+
+```
+
+DefaultSingletonBeanRegistry类中的几个特别重要的属性
+
+```java
+//一级缓存 存放完整Bean对象(实例化+初始化)
+private final Map singletonObjects = new ConcurrentHashMap<>(256);
+
+//三级缓存 存放一个lambda表达式
+private final Map> singletonFactories = new HashMap<>(16);
+
+//二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
+private final Map earlySingletonObjects = new ConcurrentHashMap<>(16);
+```
+
+> 循环依赖问题应该是出现属性填充的时候
+
+doCreateBean这个方法
+
+> 可以参照[createBeanInstance](https://github.com/yang520-bye/source-code-hunter/blob/main/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](https://github.com/doocs/source-code-hunter/blob/main/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 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;
+}
+```
+
+最后经历这个就获取到一个半成品对象所依赖的一个完整对象,然后再将完整对象注入半成品对象中。
+
+
+
+### 历程
+
+Tip:
+
+>该历程仅代表当前这个项目工程
+