当前位置: 首页 > article >正文

spring循环依赖深度源码解析

spring循环依赖深度源码解析

一,什么是循环依赖问题

简单来说循环依赖就是在spring容器中的两个Bean互相调用对方

在这里我们创建了两个对象A,B,在A中调用B,在B中调用A,这样就会产生循环依赖问题

public class A {
   private B b;

   public B getB() {
      return b;
   }

   public void setB(B b) {
      this.b = b;
   }
}
public class B {
   private A a;

   public A getA() {
      return a;
   }

   public void setA(A a) {
      this.a = a;
   }
}
<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="com.jixu.DTO.A">
      <property name="b" ref="b"></property>
   </bean>
   <bean id="b" class="com.jixu.DTO.B">
      <property name="a" ref="a"></property>
   </bean>
</beans>

在这里插入图片描述

二,什么是三级缓存

三级缓存是咋spring的DefaultSingletenBeanRegister这个类当中

// 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

// 二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

在这里最值得注意的是三级缓存,我们看一下它的类型Map<String, ObjectFactory<?>>,它的key的类型为 ObjectFactory<?>,我们进入源码来看一下这是个什么东西

// 函数式接口 --》 只有当调用getObject时候才会真正执行代码
@FunctionalInterface
public interface ObjectFactory<T> {

   /**
    * Return an instance (possibly shared or independent)
    * of the object managed by this factory.
    * @return the resulting instance
    * @throws BeansException in case of creation errors
    */
   T getObject() throws BeansException;

}

它使用了一个@FunctionalInterface也就是函数式接口,这样的话在三级缓存当中存放的就是Lambda表达式,而且只有当调用了其getObject方法的时候才会实际调用Lambda当中的代码

为什么spring要这样设计,提前暴露bean?那我们来想一个问题,如果对象是代理对象该怎么办,我们在创建的时候并不能知道该对象是代理对象还是普通对象,只有在实际调用的时候才能知道具体类型。那么函数式接口就可以完美解决这个问题,在实际调用的时候再使用getObject方法根据其类型实际创建对象。

三,全流程debug

在这里我们从AbstractApplicationContext这个类当中的refresh方法开始打断点

在这里插入图片描述

此时在我们的beanFactory当中也可以找到对应的三级缓存

在这里插入图片描述

按F8一直到preInstantiateSingletons这个方法中该方法是用来创建Bean的

在其中的beanNames当中就保存着我们所有注册的bean对象的beanDefinition信息,在这里就可以看到A,B对象,之后会循环A,B创建对象

在这里插入图片描述

在这里会进行一系列判断,之后会调用getBean方法,在getBean方法当中会调用doGetBean方法(通常以do开头的是实际执行的方法)

public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

在doGetBean当中会去判断对象在三级缓存当中是否存在

// 判断在三级缓存当中是否存在该对象
Object sharedInstance = getSingleton(beanName);
public Object getSingleton(String beanName) {
   return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            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) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

如果不存在就会去调用其createBean方法创建Bean,快进到方法位置

// 创建Bean实例
if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, () -> {
      try {
         return createBean(beanName, mbd, args);
      }
      catch (BeansException ex) {
         // Explicitly remove instance from singleton cache: It might have been put there
         // eagerly by the creation process, to allow for circular reference resolution.
         // Also remove any beans that received a temporary reference to the bean.
         destroySingleton(beanName);
         throw ex;
      }
   });
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

在这里插入图片描述

在这里会进行一个判断,判断是否为单列对象,通过getSingleton方法传入bean名称与lambda表达式回调

createBean方法。在其createbean方法中会调用doCreateBean方法执行具体的实例化及属性赋值流程

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
   instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 创建通过反射创建对象
if (instanceWrapper == null) {
   instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 获取到对象
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
   mbd.resolvedTargetType = beanType;
}

在这里插入图片描述

在doCreateBean当中会提前暴露对象,通过反射创建对象实例,其属性赋值为空。将将key=bean名称,value=lambda表达式加入三级缓存当中

这个方法的主要作用是在bean的生命周期中提供一个早期访问点,允许某些特定的处理或操作在bean完全初始化之前进行。这在需要对bean进行特殊处理,或者在bean初始化过程中需要引用同一bean的早期状态时非常有用。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

调用其populateBean方法为A的属性进行赋值

在这里插入图片描述

在这里如果属性值为另一个Bean的引用时其值的类型为runTimeReference

循环所有属性进行赋值判断其类型是否为runTimeReference如果是则调用其getBean方法获取对象

在这里插入图片描述

在这里插入图片描述

在doGetBean当中就会尝试获取B的Bean,如果Bean不存在则创建B和上述流程一样

在这里插入图片描述

最后将B的lambda加入到三级缓存当中,调用populateBean方法赋值属性

在这里插入图片描述

此时B中需要注入A

在这里插入图片描述

此时在三级缓存当中就可以查询到Bean信息,之后会调用其getObject方法回调函数

// 从单例池当中获取对象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例池当中不存在,且对象正在创建过程中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   // 从二级缓存当中获取对象
   singletonObject = this.earlySingletonObjects.get(beanName);
   // 如果二级缓存中不存在
   if (singletonObject == null && allowEarlyReference) {
      synchronized (this.singletonObjects) {
         // Consistent creation of early reference within full singleton lock
         // 再次检查
         singletonObject = this.singletonObjects.get(beanName);
         if (singletonObject == null) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null) {

               // 从三级缓存当中获取到对应的lambda表达式
               ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
               if (singletonFactory != null) {
                  // 调用其getObject方法
                  singletonObject = singletonFactory.getObject();
                  // 加入二级缓存
                  this.earlySingletonObjects.put(beanName, singletonObject);
                  // 从三级缓存当中删除
                  this.singletonFactories.remove(beanName);
               }
            }
         }
      }

在这里将bean赋值给了exposedObject这也就是所谓的提前暴露对象, 通过该方法可以判断出是否有beanPostProcesser的增强,也就是是否为代理对象对其进行代理,如果不是则返回普通对象

在这里插入图片描述

此时就生成了A的半成品对象,并加入了二级缓存,之后对属性值赋值

在这里插入图片描述

执行完毕后将B对象加入一级缓存,此时B的完整Bean对象已经生成

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

之后将B注入给A,将A对象加入一级缓存移除其二级缓存的数据


http://www.kler.cn/a/441204.html

相关文章:

  • 蓝桥杯之c++入门(一)【C++入门】
  • 工作总结:压测篇
  • Python设计模式 - 组合模式
  • 基于Springboot的智能学习平台系统【附源码】
  • 如何将 Windows 上的文件传递到 Mac 上
  • Mybatis是如何进行分页的?
  • 开发小技巧之GIT版本回退
  • Linux在Ubuntu系统下安装MySQL数据库(全网最详细)
  • 二十四、Qt之使用动态库
  • 学习笔记070——Java中【泛型】和【枚举】
  • 如何获取抖音item_get_app接口
  • 【Linux】—简单实现一个shell(myshell)
  • 快速掌握源码部署Filebeat
  • 浅谈基于单片机的计步器设计
  • 架构师之路--springboot核心类SpringApplication方法run的源码启动流程
  • 【华为OD机试真题】【2024年E卷】数值同化-队列BFS(C++/Java/Python)
  • 网络安全考题
  • 禁用硬件合成 (Hardware Composer, HWC)
  • ChatGPT搜索全新升级,向全体用户开放,近屿智能助力AI行业发展
  • Linux:入门篇——万字长篇解析
  • 生活小妙招之UE CaptureRT改
  • Qt编译MySQL数据库驱动
  • Linux 各发行版安装 ping 命令指南
  • 解决Windows Server环境下PPTX转PDF时WebP格式图片缺失
  • 程序设计考题汇总(四:SQL练习)
  • Pytorch | 从零构建GoogleNet对CIFAR10进行分类