一.spring循环依赖
1. 什么是循环依赖?
bean的生命周期前面的章节我们有讲解过大量的源码,我们粗略的分为这几步
- spring扫描class获取BeanDefintion
- spring根据BeanDefintion实例化bean
- 创建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对象
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周期
-
在创建bean之前,首先要找到对应的类并且加载
-
实例化前(执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法)
-
实例化
-
实例化后(执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法)
-
为属性赋值(执行InstantiationAwareBeanPostProcessor.postProcessProperties,InstantiationAwareBeanPostProcessor.postProcessPropertyValue后得到返回后进行applyPropertyValue方法如上图所示)
-
执行Aware接口的对应方法(invokeAwareMethods)
-
初始化前(执行BeanPostProcessor.postProcessBeforeInitialization方法)
- 初始化( 执行初始化方法)
-
初始化后(执行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循环依赖源码详细解析
- singletonObjects:缓存经过了完整生命周期的bean
- earlySingletonObjects:
缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,
就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果
要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入
earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是
没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整
生命周期的bean。 - 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注解有关资料,这里就不讲述了