spring循环依赖深入理解

本文深入探讨Spring框架如何解决循环依赖问题,特别是在setter注入场景中。通过三级缓存机制,Spring能够在单例Bean初始化的不同阶段提前暴露部分实例,避免循环依赖导致的死锁。

一、什么是循环依赖

         实例A->实例B->实例C->实例A。实例间的依赖构成闭环。spring 默认是支持循环依赖的(setter).

         

 public AbstractAutowireCapableBeanFactory() {
        this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
        this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        // 这个字段设置了DefaultLisableBeanFactory是否支持循环依赖
        this.allowCircularReferences = true;
        this.allowRawInjectionDespiteWrapping = false;
        this.ignoredDependencyTypes = new HashSet();
        this.ignoredDependencyInterfaces = new HashSet();
        this.factoryBeanInstanceCache = new ConcurrentHashMap(16);
        this.filteredPropertyDescriptorsCache = new ConcurrentHashMap(256);
        this.ignoreDependencyInterface(BeanNameAware.class);
        this.ignoreDependencyInterface(BeanFactoryAware.class);
        this.ignoreDependencyInterface(BeanClassLoaderAware.class);
}

         循环依赖分为三种:

  1. 构造器循环依赖
  2. setter循环依赖
  3. 多例循环依赖 

         其中第一种和第三种是直接报错的,spring 无法解决。所以我们说的主要是setter循环依赖。

二、 简略地说明解决方案

        spring 利用 单例Bean初始化过程的多阶段性,提前暴露了某个阶段的单例Bean,从而解决了循环依赖。

          下图比较简单地说明了一下:

           

三、源码理解

我们直接看创建Bean的源码来分析

AbstractAutowireCapableBeanFactory:278
  protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        //初始化第一步 获取到一个简单的对象,还没属性赋值
        final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
        Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
        
         // 。。。。省略的代码
         
        //判断是否提前暴漏自己:  单例 &&  允许循环依赖 && 还在初始化阶段
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
            //重要 重要  就是这里把自己的一个FactoryBean提前暴漏了,放进singletonFactories(Map)中
            this.addSingletonFactory(beanName, new ObjectFactory<Object>() {
                public Object getObject() throws BeansException {
                    return AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }
        //返回值
        Object exposedObject = bean;

        try {
            //重要步骤  初始化第二阶段  属性赋值(完成依赖注入)
            this.populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = this.initializeBean(beanName, exposedObject, mbd);
            }
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

         // 。。。省略代码

        try {
            //初始化第三阶段,注册实例
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

好了这是创建Bean的一个大体的过程。在创建A Bean的时候,把一个FactoryBean给提前暴露了。然后再注入B Bean实例的时候,还是继续创建B Bean的过程,(注意此时A的一个FactoryBean已经暴漏了)但是在给B Bean设置依赖的时候,获取A Bean 的方法里会获取到一个A 的一个factoryBean.从而完成B的初始化。

所以第二个重点的过程就是获取Bean的方法,做了什么手脚,让B获取到了一个提前暴露的A Bean

AbstractBeanFactory:108
public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
 }

protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
        final String beanName = this.transformedBeanName(name);
        //重要重要,就是这里 把提前暴漏的Bean获取到了
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        if (sharedInstance != null && args == null) {
           // 省略代码 hhh  
        } else {
            // 省略代码  下面的代码是创建Bean相关的
        }
         
        //检查是否与要求的类型匹配   跟主题无关,可跳过
        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
            try {
                return this.getTypeConverter().convertIfNecessary(bean, requiredType);
            } catch (TypeMismatchException var22) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
                }

                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        } else {
            return bean;
        }
  }

接下来我们继续看重要的一个方法getSingleton(beanName)

 public Object getSingleton(String beanName) {
        return this.getSingleton(beanName, true);
    }

  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
         //singletonObjects 这里放着Bean容器里所有的单例实例
          //因为A  Bean还没有初始化完成所以肯定是null ,而且也在初始化过程Bean的集合里
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            Map var4 = this.singletonObjects;
            //锁住这个全局对象
            synchronized(this.singletonObjects) {
                //从第二级缓存earlySingletonObjects中看下有没有,如果没有再继续找
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                     //重要  这里的singletonFactory 就是上面我们反复提到的那个提前暴露的FactoryBean 了
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        //利用factoryBean 获取到A  Bean的实例
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject != NULL_OBJECT ? singletonObject : null;
    }

 到这里相信大家应该有一定的理解了吧。

 接下来重点说下上面出现的几个重要的Map

 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 HashMap(16);

  也可以说是单例Bean实例化过程的三级缓存机制。

  1.  创建开始 把自己的一个FactoryBean放进singletonFactories(第三级缓存)中
  2. 在创建过程中其他类如果需要自己的时候,通过singletonFactories获取到FactoryBean,然后获取到实例返回,同时从第三级缓存中移除,放进第二级缓存earlySingletonObjects
  3. 初始化完成后,把实例放进一级缓存 singletonObjects,同时从三级缓存和二级缓存中移除掉
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值