spring如何解决循环依赖

   日期:2020-09-30     浏览:79    评论:0    
核心提示:概述循环依赖就是依赖关系形成环,比如最简单的循环依赖:A对象依赖B,B对象依赖A属性注入与循环依赖如果是构造器注入,如果循环依赖对象没法构建,因为还未实例化 如果是属性注入但是作用域是prototype,spring不会缓存其对象实例,也不能处理循环依赖的情况 如果是属性注入singleton的,其bean的实例化过程与属性注入过程是分开的,并且spring提供了三个map(就是大家说三级缓存)来实现。spring属性注入处理循环依赖的方式通过以下xml方式配置一个循环依赖的示例:

概述

循环依赖就是依赖关系形成环,比如最简单的循环依赖:A对象依赖B,B对象依赖A

属性注入与循环依赖

  1. 如果是构造器注入,如果循环依赖对象没法构建,因为还未实例化
  2. 如果是属性注入但是作用域是prototype,spring不会缓存其对象实例,也不能处理循环依赖的情况
  3. 如果是属性注入singleton的,其bean的实例化过程与属性注入过程是分开的,并且spring提供了三个map(就是大家说三级缓存)来实现。

spring属性注入处理循环依赖的方式

通过以下xml方式配置一个循环依赖的示例:

<bean id="person1" class="com.example.leetcode.spring.bean.Person">
    <property name="parent" ref="person2"></property>
    <property name="name" value="tom"></property>
</bean>

<bean id="person2" class="com.example.leetcode.spring.bean.Person">
    <property name="parent" ref="person1"></property>
    <property name="name" value="jack"></property>
</bean>

spring循环依赖处理几个关键位置:

  1. 获取bean对象
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;

    // 这里会检查单例bean是否已经在注册表,并返回。
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    ...
}
复制代码
  1. DefaultSingletonBeanRegistry(单例对象注册表)的几个关键属性。
    // 用来存储已经创建好的单例对象
    
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    // 用来存储单例beanname到ObjectFactory的映射
    
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    // 用来提前存储还未初始化好的单例对象
    
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  1. DefaultSingletonBeanRegistry.getSingleton()的实现.
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
  1. AbstractAutowireCapableBeanFactory.doCreateBean创建对象与注入属性
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
    ...
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    ...
    // 检查是否提前将单例bean存入缓存
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        // 这里将beanname与工厂映射放入缓存注册表中(也就是上面的singletonFactories)
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    
    ...
    // 注入依赖属性
    populateBean(beanName, mbd, instanceWrapper);
    ...
                
}

假设我们从beanfactory获取person1对象, 循环依赖处理流程如下:

  1. 通过AbstractBeanFactory.doGetBean("persion1")获取对象
  2. 因为一开始通过DefaultSingletonBeanRegistry.getSingleton()什么都没有,进入AbstractAutowireCapableBeanFactory.doCreateBean()进行创建
  3. AutowireCapableBeanFactory.doCreateBean()里面执行完创建逻辑,因为是singleton将beanname与工厂的映射加入到addSingletonFactory()到缓存
  4. 开始处理person1对象的属性依赖populateBean()
  5. 当发现person1的parent属性是一个引用时,通过beanfactory.getBean("person2")获取依赖对象(org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference)
  6. 此时进入person2的创建流程, person2也没有缓存,开始实例化并加入到addSingletonFactory()到缓存
  7. person2在通过populateBean()注入属性依赖发现依赖person1, 此时通过beanfactory.getBean("person1")获取依赖对象
  8. 此时AbstractBeanFactory.doGetBean("persion1")获取对象执行到getSingleton("person1")进行以下判断:
    • 从singletonObjects.get(beanName)获取到null
    • 进入if条件,对singletonObjects同步
    • 从earlySingletonObjects.get(beanName);获取也为null
    • 进入内层if,通过singletonFactories.get(beanName);获取到最开始bean实例化之后的beanname与工厂缓存信息
    • 获取到仅实例化完成的bean,并earlySingletonObjects.put(beanName, singletonObject);
    • 然后删除singletonFactories.remove(beanName);
  9. 此时从getSingleton("person1")返回了一个仅实例化尚未注入的bean引用
  10. person2在第7步获取到person1仅实例化未注入的对象引用。
  11. person2完成属性注入并返回。
  12. person2被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)缓存,并删除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
  13. person1在5步获取到person2的对象并完成属性注入
  14. person1对象返回(因为一开始person2获取的是person1的引用,此时person1完成注入是能看到注入后的对象)
  15. person1被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)缓存,并删除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
  16. 返回最终的person1对象

关于三个map(三级缓存)

在出现循环依赖时,三个map之间的流程如下:

  1. 先从singletonFactories获取工厂,并通过getObject获取对象并移除缓存,将对象缓存到earlySingletonObjects
  2. 通过earlySingletonObjects获取提前曝光的对象
  3. 对象创建并初始化完成之后,对象信息保留在singletonObjects并移除过earlySingletonObjects中的缓存

earlySingletonObjects二级缓存是鸡肋吗?

earlySingletonObjects缓存的目的是,通过三级缓存在获取对象会执行一些列的后置处理器,通过earlySingletonObjects来缓存提升性能。


 

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服