Spring在默认单例情况下是支持循环引用的。
@Component
public class BbService {
@Autowired
CcService ccService;
public BbService() {
System.out.println("constructor from BbService");
}
}
@Component
public class CcService {
@Autowired
BbService bbService;
public CcService() {
System.out.println("constructor from CcService");
}
}
这两个单例类互相引用,并且是非构造方法注入,就叫循环引用。
这样就形成了死循环。
但是spring解决了这个问题。
简单来说,spring是通过三级缓存来解决循环依赖的。
三级缓存其实就是三个map:
/** Cache of singleton objects: bean name --> bean instance */
//通常说的spring容器
//实际上只是单例池
//三级缓存之一:存放单例bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
//三级缓存之一:存放ObjectFactory,单例对象的工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
//三级缓存之一:存放提前暴露的对象,没有经过完整的spring bean生命周期的bean
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
至于哪是一级,哪是二级,哪是三级,有很多种说法,我也不知道该怎么定,总之,知道这三个map的作用就行了。
接下来看spring是怎么通过三级缓存解决循环依赖的。
就以上文中的BbService和CcService为例来说明。
假设spring先初始化bbService,先从getBean(”bbService“)方法开始看。
getBean()方法什么也没干,就调用了doGetBean()方法
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* ....代码段
*/
// Eagerly check singleton cache for manually registered singletons.
//从容器中取
//第一次从容器中取,肯定为null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
/**
* ...代码段
*/
}
// Create bean instance.
if (mbd.isSingleton()) {
//重载方法
//第二次从容器中取
/**第二个参数是一个lamda表达式,类型是ObjectFactory
* 等价于
* class Temp implement ObjectFactory{
* @override
* public Object getObject(){
* createBean(beanName, mbd, args);
* }
*
* private Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
* .......
* }
* }
* ObjectFactory temp = new Temp();
* getSingleton(beanName, temp);
*
* 在getSingleton方法中调用第二个参数ObjectFactory的getObject()方法就是调用这里的createBean(beanName, mbd, args)方法
* */
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
/**
* ... 代码段
*/
}
bean初始化过程中,第一次调用getSingleton(beanName)返回结果肯定为null,因为此时bean还没有实例化。
重点看第二次的重载方法getSingleton(String beanName, ObjectFactory> singletonFactory)
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 + "'");
}
//将beanName放入map中,singletonsCurrentlyInCreation,标识对应的bean正在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//创建bean
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;
}
//bean创建完成后,将beanName从map:singletonsCurrentlyInCreation中移除
afterSingletonCreation(beanName);
}
if (newSingleton) {
//将bean添加到单例池当中,
//并且将对应的bean从三级缓存中移除
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
进入创建bean的方法singletonFactory.getObject()
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
/**
* ... 代码段
*/
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
/**
* ...代码段
*/
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
/**
* ...代码段
*/
if (instanceWrapper == null) {
// 实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
/**
* ... 代码段
*/
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 判断是否支持循环依赖
// 如果支持,提前暴露bean,即将bean的工厂放入三级缓存中的singletonFactories
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//第四次调用beanPostProcessor,SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//属性注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
/**
* ... 代码段
*/
}
核心方法:
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);
}
}
}
这个方法在bean实例化之后,依赖注入之前调用,将没有完全初始化的bean的工厂放入三级缓存中的singletonFactories。
也就是说这个方法执行后,singletonFactories中会有一条数据,key=“bbService”。
然后调用populateBean(beanName, mbd, instanceWrapper)方法对bbService进行依赖注入,过程中发现依赖CcService,就会调用getBean(“ccService”)方法。
与bbService同样,在实例化之后,依赖注入之前,将没有完全初始化的bean的工厂放入三级缓存中的singletonFactories。
这时,singletonFactories中存在两条数据,key="bbService"和key=“ccService”。
然后调用populateBean(beanName, mbd, instanceWrapper)方法对ccService进行依赖注入,过程中发现依赖BbService,就会调用getBean(“bbService”)方法,这个时候与第一次调用getBean(“bbService”)就会有所不一样了。
第一次调用getBean(“bbService”)时,首先调用getSingleton(beanName)方法返回null,然后调用重载方法getSingleton(String beanName, ObjectFactory> singletonFactory)。
但是,这次调用getBean(“bbService”)时,调用getSingleton(beanName)方法的返回结果不再为null。先来看下这个getSingleton(beanName)方法。
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从单例池中取
Object singletonObject = this.singletonObjects.get(beanName);
//是否正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从三级缓存中的earlySingletonObjects取
singletonObject = this.earlySingletonObjects.get(beanName);
//判断是否支持循环依赖
if (singletonObject == null && allowEarlyReference) {
//从三级缓存中的singletonFactories取bean工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
三级缓存就是在这里发挥作用的。
1,从单例池singletonObjects中取”bbService“,肯定取不到,因为此时”bbService“还在依赖注入阶段,并没有被放入单例池当中
2,判断”bbService“是否正在创建中,返回结果为true,因为上文中有说道,在"bbService"实例化之前,会将beanName放入singletonsCurrentlyInCreation中。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
3,从三级缓存中的earlySingletonObjects中取,依然取不到
4,判断是否支持循环依赖,allowEarlyReference是传入的参数,为true。
5,从三级缓存中的singletonFactories中取bean的工厂,此时能够取到"bbService"的bean工厂,因为上文已经说过,在bean实例化之后,依赖注入之前,会调用addSingletonFactory(String beanName, ObjectFactory> singletonFactory)方法将bean的工厂放入singletonFactories
6,调用bean的工厂的getObject()方法,将结果放入三级缓存中的earlySingletonObjects,将bean的工厂从singletonFactories中移除,移除的原因是earlySingletonObjects中已经有了,就不会再从singletonFactories中取了(至于为什么在放入singletonFactories时不直接调用getObject()方法,将结果放入earlySingletonObjects,这样就不需要singletonFactories了,我也没搞清楚)。
到这里,循环依赖的问题已经基本解决了。
但是,注意,但是,特殊情况来了:
在上一篇BeanPostProcessor的文章中讲过,spring的aop是在第八次调用BeanPostProcessor时完成代理的,这个步骤实在依赖注入之后的
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
/**
* ... 代码段
*/
// Initialize the bean instance.
Object exposedObject = bean;
try {
//属性注入
populateBean(beanName, mbd, instanceWrapper);
//这个方法中第七次和第八次调用BeanPostProcessor,完成bean的初始化和aop代理
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
/**
* ... 代码段
*/
return exposedObject;
}
那么问题来了,按照这个逻辑,在上文循环依赖的过程中,ccService中注入的bbService应该是bbService的原生对象,那么在bbService有aop的情况下,ccService中的属性bbService是什么时候被替换成bbService的代理对象的呢?
@Component
@Aspect
public class MyAspect {
@Pointcut("within(com.andy.service.BbService)")
public void pointcut(){}
@Before("pointcut()")
public void before(){
System.out.println("aop-----before");
}
}
@Component
public class BbService {
@Autowired
CcService ccService;
public BbService() {
System.out.println("constructor from BbService");
}
public void aop(){
System.out.println("AaService----aop");
}
}
经过debug发现,在上文的循环依赖过程中,ccService在进行依赖注入的时候,注入的就是bbService的代理对象
这又是怎么回事呢?
debug发现,在上文第18步中objectFactory.getObject()返回的就是代理对象。
在进入objectFactory.getObject()方法研究之前,还记得上文的第5步:将bean的工厂放入singletonFactories,beanName="bbService"吗?
/**第二个参数是一个lamda表达式,类型是ObjectFactory
* 等价于
* class Temp implement ObjectFactory{
* @override
* public Object getObject(){
* getEarlyBeanReference(beanName, mbd, args);
* }
*
* private Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
* .......
* }
* }
* ObjectFactory temp = new Temp();
* getSingleton(beanName, temp);
*
* 当调用objectFactory.getObject()时,实际上调用的就是这个getEarlyBeanReference(beanName, mbd, bean)方法
* */
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
直接进入getEarlyBeanReference(beanName, mbd, bean)方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//getBeanPostProcessors()方法的结果中有一个AbstractAutoProxyCreator,完成aop的类
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
这里就是BeanPostProcessor中讲到的第四次调用。
进入AbstractAutoProxyCreator的getEarlyBeanReference(exposedObject, beanName)方法,这个方法的作用就是提前完成aop并将bean记录在earlyProxyReferences中
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//将提前完成aop的bean记录下来
this.earlyProxyReferences.put(cacheKey, bean);
//真正完成aop的方法
return wrapIfNecessary(bean, beanName, cacheKey);
}
所以objectFactory.getObject()返回的就是代理对象。
然后在BeanPostProcessor的第八次调用时,调用到AbstractAutoProxyCreator的postProcessAfterInitialization(bean,beanName)时,首先判断earlyProxyReferences中是否存在bean,如果存在,说明已经完成aop了,就直接返回,如果不存在,再进行aop,然后返回。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//判断earlyProxyReferences中是否存在该bean
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
所以循环依赖的情况下,aop是会提前完成的。
本文第一句话说道:Spring在默认单例情况下是支持循环引用的。
那么在什么情况下不支持循环依赖呢?
在bean实例化完成后,将bean的工厂放入singletonFactories之前,有一个if判断
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
//条件为true时,才会将bean的工厂放入singletonFactories
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//第四次调用beanPostProcessor,SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
earlySingletonExposure的值由三个条件决定:
1,mbd.isSingleton(),这个一定为true,现在研究的就是单例bean的循环依赖,只有单例bean才会存在循环依赖。
2,this.allowCircularReferences
3,isSingletonCurrentlyInCreation(beanName)这个也一定为true,因为上文循环依赖的第三步。
所以关键就看this.allowCircularReferences,这是AbstractAutowireCapableBeanFactory中的一个私有属性,默认为true,spring中也没有地方修改这个值,所以说spring默认支持循环依赖。
/** Whether to automatically try to resolve circular references between beans */
private boolean allowCircularReferences = true;
但是spring也提供了api来修改这个值
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
//一定要在refresh()方法之前设置,因为refresh()结束后,bean都初始化完了,在设置就没有意义
ac.setAllowCircularReferences(false);
ac.register(AppConfig.class);
ac.refresh();
}
}
运行结果如下:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bbService': Unsatisfied dependency expressed through field 'ccService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ccService': Unsatisfied dependency expressed through field 'bbService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bbService': Requested bean is currently in creation: Is there an unresolvable circular reference?
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bbService': Unsatisfied dependency expressed through field 'ccService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ccService': Unsatisfied dependency expressed through field 'bbService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bbService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1353)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:500)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:890)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:556)
at com.andy.test.Test.main(Test.java:21)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ccService': Unsatisfied dependency expressed through field 'bbService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bbService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1353)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:500)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1058)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
... 13 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bbService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:349)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1058)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
... 26 more
spring应该是没有提供通过配置关闭循环依赖的方式,所以只能通过编码的方式。
实际开发中也应该没人闲的蛋疼去关闭循环依赖,这里写出来只是为了加深对循环依赖源码的研究。