spring源码bean生命周期篇 五 如何解决循环依赖

一.spring循环依赖

1. 什么是循环依赖?

bean的生命周期前面的章节我们有讲解过大量的源码,我们粗略的分为这几步

  1. spring扫描class获取BeanDefintion
  2. spring根据BeanDefintion实例化bean
  3. 创建bean之前需要实例化对象,实例化后填充原始对象中的属性(依赖注入)
@Service
public class B {
    
    @Autowired
    public A a;
}

@Service
public class A {
    @Autowired
    private B b;
}

如下图所示:

以先创建bean a为例,实例化后填充属性b时,发现bean b还没被创建不在单例池(singletonObjects)中,这时侯会去创建bean b,在实例化对象之后,需要填充属性a,这时候发现spring 的单例池(singletonObjects) 中也没有bean a,又需要创建bean A;

创建bean a 需要创建 bean b ,创建bean a 需要创建 bean b,不管先创建bean a 还是先创建bean b这样造成了死循环, 如果不处理的话,两个bean都无法创建,这时侯我们该如何打破僵局呢?

singletonObjects:中缓存的是已经经历了完整生命周期的bean对象![](https://img-blog.csdnimg.cn/65ba243010484ffbb3068e92e2592d93.png

2. 如何打破循环依赖的僵局

在多数情况下,在实例化得到的对象,和最终的bean是同一个对象,只是实例化的对象没有进行属性填充以及初始化等步骤。因此我们可以提前暴露bean的方式解决

我们可以缓存实例化的得到的对象,这样的步骤就如下图所示,在spring源码中,缓存早期bean容器名称为earlySigthonObjects

1. bean a 实例化后放入存放早期bean的容器earlySigthonObjects中

2. 创建bean a 的过程中需要填充属性b,存放完整bean两个容器中都没有 bean b,触发创建 bean b

3. bean b 实例化 放入早期bean容器earlySigthonObjects中,并且填充属性a,拿出1步骤存放earlySigthonObjects的早期bean a,bean b顺利被创建

4. bean a 即可创建完成

以创建bean B为例,如下图所示:

在这里插入图片描述

3. Spring Aop怎么解决循环依赖

在讲这个课题之前,我们回忆一下bean周期

  1. 在创建bean之前,首先要找到对应的类并且加载

  2. 实例化前(执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法)

  3. 实例化

  4. 实例化后(执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法)

  5. 为属性赋值(执行InstantiationAwareBeanPostProcessor.postProcessProperties,InstantiationAwareBeanPostProcessor.postProcessPropertyValue后得到返回后进行applyPropertyValue方法如上图所示)

  6. 执行Aware接口的对应方法(invokeAwareMethods)

  7. 初始化前(执行BeanPostProcessor.postProcessBeforeInitialization方法)

  8. 初始化( 执行初始化方法)
  9. 初始化后(执行BeanPostProcessor.postProcessAfterInitialization方法)

在初始化过程中:

BeanPostProcessor.postProcessAfterInitialization方法和BeanPostProcessor.postProcessBeforeInitialization中对bean可以进行处理返回新的bean代替原来的bean

而AOP就是通过一个BeanPostProcessor来实现的,这个BeanPostProcessor就是
AnnotationAwareAspectJAutoProxyCreator,它的父类是AbstractAutoProxyCreator,而在设置了切面,那么这个类最终就需要生成一个代理对象,在之前的章节我们也有讲过这个类。

基于上面的场景想一个问题:

如下如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象 此时就会出现,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,但实际上注入的是AOP代理之前的原始bean。

如下图所示:

在这里插入图片描述

但是AOP可以说是Spring中除开IOC的另外一大功能,而循环依赖又是属于IOC范畴的,所以这两大功 能想要并存,Spring需要特殊处理,为了解决Spring Aop的循环依赖,我们可以提前暴露AOP之后的代理对象来解决

解决方案:

引入singletonFactories(第三级缓存)把AOP的步骤提前:

singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,
生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory
是一个函数式接口,所以支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd,
bean)
getEarlyBeanReference对应的逻辑:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getEarlyBeanReference


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;
	}

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.getEarlyBeanReference

	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		//当前bean放入earlyProxyReferences代表已经进行了AOP
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}


 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//缓存是不需要AOP的对象,直接返回
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 获取所有可以应用到当前bean的切面逻辑
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//创建代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
  
  public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
		   //进行AOP的不需要再次创建bean的代理对象
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

二.spring循环依赖源码详细解析

  1. singletonObjects:缓存经过了完整生命周期的bean
  2. earlySingletonObjects

    缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,
    就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果
    要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入
    earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是
    没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整
    生命周期的bean。

  3. singletonFactories

缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean 的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达 式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出 现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后 直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖 (当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行 Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么 执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。

4. 其实还要一个缓存,就是 earlyProxyReferences,它用来记录某个原始对象是否进行过AOP 了

下图是先解决bean a 和bean b循环依赖的证据 ,先创建a的流程如图所示

在这里插入图片描述

getBean(String name)

getBean调用了两个getSingleton方法

  • 入参数只有一个beanName,当前方法是去看看spring容器中有没有当前名为beanName的bean,如果没有要判断当前bean是否在标记正在创建,如果标记为创建才会去找二级缓存,alowEarlyReference参数默认为true并二级缓存为null,才会找三级缓存获取早期bean

  • 入参有两个参数,一个为beanName,一个为ObjectFactory,主要是创建bean,并把当前bean标记为正在创建

处理bean A和Bean B循环依赖的流程,以先创建Bean A为例

整个逻辑都在getBean(a)方法中

1. 调用getSingleton(a)从一二三级缓存中找bean A,这时候肯定是没有的,调用第二个getSingleton方法创建bean A,并标记bean A正在创建

2.创建bean A的过程中需要实例化A对象,并根据实例化的对象生成ObjectFactory,放入第三缓存

3.创建bean A的过程中需要填充属性b ,触发调用方法getBean(b)获取bean b

4.调用getSingleton(b),一二三级缓存中找bean A,这时候肯定是没有的,这时候调用第二个getSingleton方法创建Bean B,并标记bean B正在创建

5.创建bean B的过程中需要实例化B对象,并根据实例化的对象生成ObjectFactory,放入第三缓存

6.创建bean B的过程中需要填充属性a,这个时候会调用getBean(a)方法,但是与第一步不同的是第三缓存中可获得早期的bean A对象给属性a赋值

7.创建bean B成功后给bean A 的属性b赋值,bean A也可以创建成功

org.springframework.beans.factory.support.AbstractBeanFactory
<T> T  getBean(String name){
   Object bean = getSingleton(beanName);
 
   if(bean == null){
          //alreadyCreated.add(beanName) alreadyCreated存储的已经被创建过一次的beanName
          markBeanAsCreated(beanName);
        //获取bean定义
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    	if (mbd.isSingleton()) {
    	       //创建bean,入参 String beanName,ObjectFactory factory
				sharedInstance = getSingleton(beanName, () -> {return createBean(beanName, mbd, args);
		}				
	}			
}
protected void markBeanAsCreated(String beanName) {
		if (!this.alreadyCreated.contains(beanName)) {
			synchronized (this.mergedBeanDefinitions) {
				if (!this.alreadyCreated.contains(beanName)) {
					// Let the bean definition get re-merged now that we're actually creating
					// the bean... just in case some of its metadata changed in the meantime.
					clearMergedBeanDefinition(beanName);
					this.alreadyCreated.add(beanName);
				}
			}
		}
	}


getSingleton(String name)

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(beanName)
代码经过简化

  public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
         //从spring一级缓存中获取bean
		Object singletonObject = this.singletonObjects.get(beanName);
		//以及缓存为空,从第二级缓存中获取bean
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				//二级缓存为null,如果allowEarlyReference为true,从三级缓存拿出singletonFactory,并执行Object方法,其返回结果放入二级缓存,并从三级缓存去掉
				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;
	}
	

getSingleton(String name, ObjectFactory<?> singletonFactory)

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(beanName,ObjectFactory)
代码经过简化

 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
			    //singletonsCurrentlyInCreation.add(beanName)
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				try	{
				     //结合上面的代码。实际上调用的是createBean(beanName, mbd, args)
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				finally {
				    //singletonsCurrentlyInCreation.remove(beanName)
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
				//singletonObjects.put(beanName, singletonObject);
				 addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}
	
   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);
		}
	}
接下来调用create方法

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
			BeanWrapper instanceWrapper = null;
			if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
			final Object bean = instanceWrapper.getWrappedInstance();
		    Class<?> beanType = instanceWrapper.getWrappedClass();
		    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		    //isSingletonCurrentlyInCreation=>singletonsCurrentlyInCreation.contains(beanName)
		    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		    if (earlySingletonExposure) {
		       //放入第三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
			}
			Object exposedObject = bean;
			//填充bean的属性
			populateBean(beanName, mbd, instanceWrapper);
			//初始化bean
			exposedObject = initializeBean(beanName, exposedObject, mbd);
			if (earlySingletonExposure) {
			 //从第二级缓存中获取当前bean,
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				     //this.dependentBeanMap.get(beanName),在bean是初始化后进行属性填充之后会注册依赖和被依赖的关系,往dependentBeanMap新增依赖关系
				     //以Demo 创建Bean A 为例,beanName为a,需要注入的属性值为bean b,所以获取到的dependentBeans为b
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
					     //并且bean b 至少触发创建过
					    // bean b已经开始创建,那么bean b注入的早期的bean对象,而不是经过整个生命周期的bean对象
						if  (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		
		}
		}
}

protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
		if (!this.alreadyCreated.contains(beanName)) {
			removeSingleton(beanName);
			return true;
		}
		else {
			return false;
		}
	

三.spring循环依赖问题的再度解决

在初始化过程中:

BeanPostProcessor.postProcessAfterInitialization方法和BeanPostProcessor.postProcessBeforeInitialization中对bean可以进行处理返回新的bean代替原来的bean,上述我们只处理了AOP有关的基于BeanPostProcessor.postProcessAfterInitialization,并不代表所有的BeanPostProcessor.postProcessAfterInitialization的都没有循环依赖问题

这里我们先上demo,根据上述讲解的源码进行分析:

@Service
public class A {
    @Autowired
    private B b;
}
@Service
public class B {
    @Autowired
    public A a;
}
@Component
public class BeanPostProcessorD implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName){
        if (bean instanceof B){
            B  b = new B();
             BeanUtils.copyProperties(bean, b);
             return b;
        }
        return bean;
    }
}

先创建bean a

在这里插入图片描述

先创建bean b
在这里插入图片描述
以当前demo来说,先创建bean a会抛出BeanCurrentlyInCreationException,而先创建bean b却不会,所以可能会出现开发环境不同,bean 的创建顺序不同导致有的同事可以正常启动项目,而有的会抛出BeanCurrentlyInCreationException终止项目运行。
解决方法加上@lazy注解,具体可查阅lazy注解有关资料,这里就不讲述了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值