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获取
- 最后的实例缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
- 早期实例缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#earlySingletonObjects
- 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的时候执行了哪些操作
可以看到做了如下的一些操作和缓存
- 标记自己在创建中
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation
- 实例化对象并缓存到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#factoryBeanInstanceCache中
- 添加了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"都完成自己的生命周期
早期对象是什么?
- 是自己或者自己的代理(如果有aop)
- 且代理逻辑只会执行一次
对于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
方法中
总结循环依赖实现依靠什么
- 依靠实例化和属性依赖注入是分开的
- 依赖各种缓存和逻辑标记,绝不是网上说的只记住三级缓存那么简单。可以看到实例化出来的raw bean要缓存的,代理出来的早期对象也要缓存的…
所以回答这个问题,需要更加细致一些。
最后可以看到spring bean循环依赖是有条件的,过程是复杂的;工作中不要用了,自己也会绕晕,看到其它人写了,最好改下设计。
原文地址:https://blog.csdn.net/qq_26437925/article/details/145224918
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!