zoukankan      html  css  js  c++  java
  • 流程图加源码方式理解Spring如何解决循环依赖

    抛个问题

    为什么构造器的循环依赖不能解决,setter循环依赖可以解决?

    构造器的依赖,自定义了构造方法,且构造方法中依赖其他Bean。

    public class BeanC {
    
        private BeanA beanA;
    
        public BeanC(BeanA beanA) {
            this.beanA = beanA;
        }
    }
    

    前驱知识点

    我们平常使用最多的Spring容器ApplicationContext初始化时会实例化所有的单例Bean。

    Bean默认加载方式为懒加载方式

    Bean的作用域默认为单例

    什么是循环依赖

    多个Bean之间的依赖关系形成闭环。如下面的例子:BeanA依赖BeanB,BeanB依赖BeanA。导致Spring在实例化时会发现有循环依赖。

    public class BeanA {
        private BeanB beanB;
    
        public BeanB getBeanB() {
            return beanB;
        }
    
        public void setBeanB(BeanB beanB) {
            this.beanB = beanB;
        }
    }
    
    public class BeanB {
        private BeanA beanA;
    
        public BeanA getBeanA() {
            return beanA;
        }
    
        public void setBeanA(BeanA beanA) {
            this.beanA = beanA;
        }
    }
    

    循环依赖具体在哪发生

    获取Bean的大致过程

    循环依赖问题发生在设置Bean属性(populateBean),初始化Bean时若发现依赖其他Bean则会递归去调用get(其他Bean)直至所有依赖的Bean都初始化完成再设置本身的依赖。

    以上面例子为例简单看一下 get(BeanA)的流程(setter依赖方式):

    解决方式

    Spring解决循环依赖浓缩为一句话为:Eagerly cache singletons to be able to resolve circular references,即提前将已实例化的但还未设置依赖的bean实例缓存起来,即实例化之后设置依赖属性之前。

    解决的点在实例化Bean doCreateBean这一步

    解决后的过程:

    需要注意的几点:

    • 从临时Map获取的Bean实例时仍未初始化完成的,还未设置属性值。

    • BeanB初始化完成时拿到的仍是BeanA未完全初始化的实例

    • BeanA递归调用获取依赖的BeanB,BeanB初始化完成后,回到了设置BeanA属性方法

    • 当BeanA初始化完成后,此时BeanA和BeanB才算是真正的初始化完成。

    • BeanB从临时缓存拿的BeanA实例和实例化BeanA的实例是同一个,java的引用嘛

    源码解读

    注:源码基于org.springframework:spring-beans:5.2.5.RELEASE

    友情提示:只列出了关键的源码。不要试图理解每一步源码的逻辑,spring的源码可能一行源码中包含了多个知识点,这样只会越陷越深。所以我们只需要理解关键步骤即可。

    public abstract class AbstractBeanFactory{
      
      //入口方法,可以从该方法一步步跟进
      public Object getBean(String name) throws BeansException {
    		return doGetBean(name, null, null, false);
    	}
    }
      protected <T> T doGetBean(final String name, 
                                @Nullable final Class<T> requiredType,
    														@Nullable final Object[] args, boolean typeCheckOnly) 
        												throws BeansException {
        
        //先从缓存中获取bean实例
    		Object sharedInstance = getSingleton(beanName);
        if (sharedInstance == null) {
          //缓存中没有则创建Bean
          return createBean(beanName, mbd, args);
        }
      }
      
      //先从缓存中获取bean实例,singletonFactories为临时缓存Map
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //singletonObjects保存已经加载好的Bean实例
    		Object singletonObject = this.singletonObjects.get(beanName);
        //此时Bean还未初始化为null,isSingletonCurrentlyInCreation判断beanName是否为正在创建
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			synchronized (this.singletonObjects) {
    				singletonObject = this.earlySingletonObjects.get(beanName);
    				if (singletonObject == null && allowEarlyReference) {
              //singletonFactories缓存正在创建的A实例,实例化时会put Bean实例
    					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    					if (singletonFactory != null) {
    						singletonObject = singletonFactory.getObject();
    						this.earlySingletonObjects.put(beanName, singletonObject);
    						this.singletonFactories.remove(beanName);
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
        
        //createBean方法调用了doCreateBean
        protected Object doCreateBean(final String beanName, 
                                      final RootBeanDefinition mbd, final @Nullable 
                                      Object[] args) throws BeanCreationException {
            // Instantiate the bean.
            //实例化Bean,下面代码段不需要重点关注
            BeanWrapper instanceWrapper = null;
            if (mbd.isSingleton()) {
              instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
            }
            if (instanceWrapper == null) {
              instanceWrapper = createBeanInstance(beanName, mbd, args);
            }
            final Object bean = instanceWrapper.getWrappedInstance();
            Class<?> beanType = instanceWrapper.getWrappedClass();
            
          	// Eagerly cache singletons to be able to resolve circular references
    				// even when triggered by lifecycle interfaces like BeanFactoryAware.
            //关键点  判断 是否为单例&&是否允许循环依赖&&且Bean是否正在创建中
            boolean earlySingletonExposure = (mbd.isSingleton() 
                                              && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
            if (earlySingletonExposure) {
              //***解决循环依赖关键点,缓存正在创建的实例
              addSingletonFactory(beanName, 
                                  () -> getEarlyBeanReference(beanName, mbd, bean));
            }
          
            try {
              populateBean(beanName, mbd, instanceWrapper);
              exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
    
        //将实例化后的Bean放入临时缓存Map  singletonFactories,对应getSingleton方法看
        protected void addSingletonFactory(String beanName, 
                                           ObjectFactory<?> singletonFactory) {
          synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
              //缓存实例,对应getSingleton方法中的get
              this.singletonFactories.put(beanName, singletonFactory);
              this.earlySingletonObjects.remove(beanName);
              this.registeredSingletons.add(beanName);
            }
          }
    		}
        
    		//设置Bean的依赖 递归去获取依赖的Bean
        protected void populateBean(String beanName, RootBeanDefinition mbd,
                                    @Nullable BeanWrapper bw) {
          if (resolvedAutowireMode == AUTOWIRE_BY_NAME 
                || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
              //设置Bean的属性,这里以通过name设置举例。
              autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
              autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
    			}
        }
        
        protected void autowireByName(String beanName, AbstractBeanDefinition mbd, 
         															 BeanWrapper bw, MutablePropertyValues pvs) {
          String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
          for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
              //若有依赖则继续获取依赖的Bean。
              Object bean = getBean(propertyName);
            }
          }
       	}
    

    回到开始的问题

    相信将上面的流程看完就明白了为什么spring不能解决构造器的循环依赖了。解决循环的关键点在于使用Bean默认的构造方式先实例化Bean,然后将实例Bean临时缓存起来,让其依赖的Bean去获取。而构造器方式需要先获取依赖的Bean,然后才能自定义的构造器创建自己的Bean实例,所以无法解决循环依赖问题。

    如有不实,还望指正

  • 相关阅读:
    GyPSii API PHP应用初探
    无缝滚动图片的一个简单封装
    Linux设置固定IP
    DIV卷帘效果示例
    vsftp安装配置
    PHP判断FORM来的数据是否为整数
    Linux下设置apache开机启动
    从Discuz提取的数据库和模板操作文件,很容易使用哦
    discuz 表情的提取
    IE6、IE7浮动层被下面的动挡住的问题
  • 原文地址:https://www.cnblogs.com/LuxBai/p/12680910.html
Copyright © 2011-2022 走看看