diff --git a/README.md b/README.md index 81c3c25..1360444 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [BeanFactoryPostProcessor](/docs/Spring/IoC/BeanFactoryPostProcessor.md) - [BeanPostProcessor](/docs/Spring/IoC/BeanPostProcessor.md) - [Spring BeanFactory 源码解析](/docs/Spring/clazz/Spring-beanFactory.md) +- [循环依赖](/docs/Spring/IoC/循环依赖.md) ### AOP diff --git a/docs/Spring/IoC/循环依赖.md b/docs/Spring/IoC/循环依赖.md new file mode 100644 index 0000000..d86972a --- /dev/null +++ b/docs/Spring/IoC/循环依赖.md @@ -0,0 +1,268 @@ +# 循环依赖 + +一个对象依赖对象闭环到自己 + +> 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](/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 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) diff --git a/images/spring/循环依赖.png b/images/spring/循环依赖.png new file mode 100644 index 0000000..ddd1b50 Binary files /dev/null and b/images/spring/循环依赖.png differ