Spring循环依赖

176 阅读4分钟

循环依赖说明

  • 最简单的循环依赖:A依赖B,B依赖A,两者会相互依赖
  • 稍微复杂一点的循环依赖:A依赖B、C,B依赖A、C,C依赖A、B,三者之间相互依赖

Spring解决的循环依赖的前置条件

  • Spring初始化时,可以正确处理循环依赖的问题,但是只是要求bean是单例的,而且是通过属性值注入的方式。以下两种情况出现循环依赖,Spring也解决不了:
    • 出现循环依赖的bean不是单例的
    • 循环依赖的属性值是通过构造函数注入的(该属性值存在于该类的构造函数中)

Spring一些基础性知识说明(解决循环依赖的基础)

  • Spring有三种实例化对象的方式:
    • 特殊的构造方法
    • 无参的默认构造方法
    • 工厂方法(factory-method)
  • Spring在进行填充属性的操作之前,已经完成了对象的实例化(尽管这个bean所有的属性都为空)
  • Spring填充属性的操作具体是由InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues方法完成的,具体的类:
    • @Resource注解是由CommonAnnotationBeanPostProcessor类解析注入的
    • @Autowired、@Value、@inject注解是由AutowiredAnnotationBeanPostProcessor类解析注入的
  • Spring容器 DefaultSingletonBeanRegistry类一些属性的说明:
  • earlySingletonObjects: Map<String, Object> 存放原始的bean对象用于解决循环依赖,注意:存到里面的对象还没有被填充属性
  • singletonFactories:Map<String, ObjectFactory<?>> 存放 bean工厂对象解决循环依赖
  • singletonObjects:Map<String, Object> 用于存放完全初始化好的 bean从该缓存中取出的 bean可以直接使用
  • singletonsCurrentlyInCreation:Set 正在创建的bean名称
  • registeredSingletons:Set 已经创建的单例bean的名称

Spring解决循环依赖的流程概述

  • 在bean进行创建前,会给bean打上正在创建的标签(singletonsCurrentlyInCreation对象中加入这个beanName)

     DefaultSingletonBeanRegistry#
     
     public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){
     		...
     }
     
     protected void beforeSingletonCreation(String beanName) {
    		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
    			throw new BeanCurrentlyInCreationException(beanName);
    		}
    	}
     
    
  • 在bean实例化以后会将这个bean提前进行暴露(会将bean放入singletonFactories和registeredSingletons属性中)

    AbstractAutowireCapableBeanFactory#
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    			throws BeanCreationException {
    if (earlySingletonExposure) {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Eagerly caching bean '" + beanName +
    						"' to allow for resolving potential circular references");
    			}
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    }
    
    DefaultSingletonBeanRegistry#
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    		Assert.notNull(singletonFactory, "Singleton factory must not be null");
    		synchronized (this.singletonObjects) {
    			if (!this.singletonObjects.containsKey(beanName)) {
    				this.singletonFactories.put(beanName, singletonFactory);
    				this.earlySingletonObjects.remove(beanName);
    				this.registeredSingletons.add(beanName);
    			}
    		}
    	}
    
  • 在进行属性注入时populateBean(beanName, mbd, instanceWrapper)时,会判断属性的类型,进行类型转换时,会从容器中获取对应的bean,如果没有,就会进入创建流程

    //以 AutowiredAnnotationBeanPostProcessor为例说明属性注入
    1. AutowiredAnnotationBeanPostProcessor# public PropertyValues postProcessPropertyValues(
    			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException;
    2. InjectionMetadata# public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable;
    3. AutowiredAnnotationBeanPostProcessor# protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable;
    4.DefaultListableBeanFactory# public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    									@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
    5.DefaultListableBeanFactory# public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
    									  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    6. DependencyDescriptor#
    public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
    			throws BeansException {
    
    		return beanFactory.getBean(beanName);
    	}
      
    7. ...
    
  • 如果一个bean正在创建,这个bean是可以被获取的,会从singletonFactory中进行获取。

    1.  AbstractBeanFactory# protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    							  @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException;
    2. DefaultSingletonBeanRegistry#  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		//从map中获取bean如果不为空直接返回,不再进行初始化工作
    		//讲道理一个程序员提供的对象这里一般都是为空的
    		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;
    	}
    

附加说明

  • SmartInstantiationAwareBeanPostProcessor接口中getEarlyBeanReference方法中可以对提前暴露的bean进行处理

    • 比如说处理aop的类AnnotationAwareAspectJAutoProxyCreator就会在getEarlyBeanReference对提前进行代理(如果需要的话)
  • Spring解决循环依赖引入了singletonFactories和earlySingletonObjects两个属性,其实如果只是处理前面说的最简单的那种循环依赖(两个对象之间),其实只需要singletonFactories属性就能够完成对应的操作。只有解决多个对象之间的循环依赖才会用到earlySingletonObjectss属性,主要是由于Spring对于提前暴露的bean也提供了接口进行前置化处理(上一条提到的AOP),为了避免这些处理重复进行所以才会用到earlySingletonObjects属性进行缓存处理好的前置对象,而不仅仅是获取对象的singletonFactories方法。

    # DefaultSingletonBeanRegistry
    @Nullable
    	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		//从map中获取bean如果不为空直接返回,不再进行初始化工作
    		//讲道理一个程序员提供的对象这里一般都是为空的
    		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;
    	}