自学内容网 自学内容网

spring中bean的循环依赖细节描述

首先,循环依赖不是一件好事,设计上几乎不会这么设计。但是总有时候要碰到一起奇怪的循环依赖。

spring bean循环依赖之所以能实现,也是有条件的,构造函数的依赖显然不行。而bean生命周期的实例化属性设置是分阶段的,所以能够解决循环依赖。

测试代码

a 依赖 b (a有代理)
b 依赖 a, c
c 依赖 a

附测试代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class A {
    @Autowired
    B b;

    public A() {
        System.out.println("A()");
    }

    public void say(){
        System.out.println("say A");
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class B {

    @Autowired
    A a;

    @Autowired
    C c;

    public B() {
        System.out.println("B()");
    }

    public void sayAC() {
        System.out.println("A:" + a + ",C:" + c);
    }

}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class C {

    @Autowired
    A a;

    public C() {
        System.out.println("C()");
    }

}

代理A的方法

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;

@Aspect
@Service
public class LogAspect {
    @Before("execution(public * com.aop.dependency..*.say(..))")
    public void before() {
        System.out.println("... before say...");
    }

}

测试

@EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.aop.dependency")
public class ConfigOne {
}

@Test 
public void test() throws Exception {
       ApplicationContext ctx =
               new AnnotationConfigApplicationContext(ConfigOne.class);

A a = (A) ctx.getBean("a");
a.say();

((AnnotationConfigApplicationContext) ctx).close();
}

debug循环依赖逻辑

在这里插入图片描述

doGetBean方法和其第一句的getSingleton(beanName, true)方法

bean获取逻辑在:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

其中第一个方法就是getSingleton(beanName, true),如下,有几个级别的缓存map获取

  1. 最后的实例缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
  2. 早期实例缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#earlySingletonObjects
  3. lambda表达式的工厂缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonFactories
/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
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;
}

bean “a” 第一次getBean的时候执行了哪些操作

可以看到做了如下的一些操作和缓存

  1. 标记自己在创建中
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation
  2. 实例化对象并缓存到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#factoryBeanInstanceCache中
  3. 添加了singletonFactorie的lambda表达式,即所谓的第3级缓存

问题1: singletonFactory的lambda表达式什么时候缓存的

在第一次getBean"a"的时候,生命周期里面添加的

在这里插入图片描述

lambda表达式为:

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

/**
 * Obtain a reference for early access to the specified bean,
 * typically for the purpose of resolving a circular reference.
 * @param beanName the name of the bean (for error handling purposes)
 * @param mbd the merged bean definition for the bean
 * @param bean the raw bean instance
 * @return the object to expose as bean reference
 */
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;
}

补充问题2:怎么执行到doCreateBean生命周期方法的

如下图,也用了一个lambda表达式执行
在这里插入图片描述

/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

先进行标记是在创建中
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation

然后执行singletonFactory.getObject();即开始执行lambda表达式得到bean实例

接着会判断是否FactoryBean

最后的对象则加入到singletonObjects缓存中,并清除其它缓存

/**
 * Add the given singleton object to the singleton cache of this factory.
 * <p>To be called for eager registration of singletons.
 * @param beanName the name of the bean
 * @param singletonObject the singleton object
 */
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);
}
}

所以不要混乱了

“a” 到 “b” 到 “a” ,“a”第二次doGetBean

第二次执行因为已经缓存了singletonFactorie,所以要执行lamdb表达了

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

从方法命名可以看到是得到一个早期对象,执行完成后会发现已经是一个代理对象了,因为本例中bean"a"是使用了aop的, (代码中称为sharedInstance

在这里插入图片描述

且第二次执行不会执行doCreateBean生命周期方法了

而是对早期对象执行org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance方法并返回

"b"到“c”到“b”, "b"第二次doGetBean

如果没有代理,可以发现"b"还是"b"
在这里插入图片描述

“a”到“b”(“a”, “c”) 到“c” 到“a”, "a"第三次doGetBean

第三次的时候,注解从earlySingletonObjects早期对象缓存取出来

最后"c",“b”,"a"都完成自己的生命周期

早期对象是什么?

  1. 是自己或者自己的代理(如果有aop)
  2. 且代理逻辑只会执行一次

对于spring的了解,我们也应该知道BeanPostProcessor是实现bean代理的关键,而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);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}

代理关键执行则是在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary方法中

在这里插入图片描述

总结循环依赖实现依靠什么

  1. 依靠实例化和属性依赖注入是分开的
  2. 依赖各种缓存和逻辑标记,绝不是网上说的只记住三级缓存那么简单。可以看到实例化出来的raw bean要缓存的,代理出来的早期对象也要缓存的…

所以回答这个问题,需要更加细致一些。

最后可以看到spring bean循环依赖是有条件的,过程是复杂的;工作中不要用了,自己也会绕晕,看到其它人写了,最好改下设计。


原文地址:https://blog.csdn.net/qq_26437925/article/details/145224918

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!