-
前言
源码分析spring创建单例bean循环依赖怎么解决? 循环依赖和aop同时发生时怎么解决的?为什么使用三级缓存?
一.什么是spring循环依赖
@Component
public class AService {
@Autowired
private BService bService;
@Transactional
public void test() {
bService.test();
}
}
@Component
public class BService {
@Autowired
private AService aService;
public void test() {
aService.test();
}
}
可以看到AService和BService互相是对方的属性,假如AService先创建,那么创建AService时会注入属性BService,这时spring容器又会去创建BService,创建BService时又会注入属性AService这时又会去创建AService,就形成了循环依赖。另外自引用(AService注入AService),间接引用(A->B->C-A)也是循环依赖.
同时注入的属性可能是代理类比如BService注入的AService需要事务代理(test方法有事务注解@Transactional),那在创建AService的哪个阶段会创建代理类呢?
bean的生命周期包括实例化,属性注入,初始化,销毁,只有初始化完成的bean才能被正常使用。
spring只解决了单例bean的循环依赖问题,没有解决原型bean的循环依赖问题,它的主要思想就是把没有初始化完成的bean放入一个map集合中,属性注入就是一个对象地址引用,对象实例化后会分配内存地址,发生循环依赖时就可以从map中获取提前暴露的bean,从而打破循环依赖条件最后所有的bean都能初始化完成。而原型bean在循环依赖时每次创建都是新的对象,所以无法通过提前暴露的方式解决,以下分析过程都是按生成单例bean为前提。
下面通过源码分析循环依赖的解决过程
2.spring容器刷新过程
单例bean的创建发生在AbstractApplicationContext的refresh方法中
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前准备设置其启动日期和活动标志等。
prepareRefresh();
// 创建BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器
prepareBeanFactory(beanFactory);
try {
// 允许在某些ApplicationContext实现中注册特殊的BeanPostProcessor等
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor如ConfigurationClassPostProcessor扫描所有的bean
invokeBeanFactoryPostProcessors(beanFactory);
// 注册后置处理器BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化 MessageSource
initMessageSource();
// 初始化事件广播
initApplicationEventMulticaster();
// 重写该方法以添加特定于上下文的刷新工作,如 springboot中
//AnnotationConfigServletWebServerApplicationContext嵌入tomcat
onRefresh();
// 注册事件监听ApplicationListener
registerListeners();
// 遍历所有已经注册的BeanDefinition创建bean
finishBeanFactoryInitialization(beanFactory);
// 完成此上下文的刷新,调用 LifecycleProcessor 的 onRefresh() 方法并发布
//ContextRefreshedEvent事件等
finishRefresh();
}
循环依赖发生在bean创建过程,finishBeanFactoryInitialization(beanFactory)就是创建bean的
二.单例bean的创建过程
finishBeanFactoryInitialization内部最终调用org.springframework.beans.factory.BeanFactory#getBean(java.lang.String)方法
BeanFactory默认实现DefaultListableBeanFactory,看下通过beanName创建bean的方法
getBean(beanName)
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
具体的创建过程是getBean(beanName),getBean会调用doGetBean:
doGetBean
//只保留关键源码
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//当前bean是FactoryBean,那么要从FactoryBean获取最终bean,可先忽略
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
if (mbd.isSingleton()) {
//创建单例bean,核心的创建逻辑在createBean方法中
sharedInstance = getSingleton(beanName, () -> {
try {
//创建bean的核心逻辑
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
//当前bean是FactoryBean,那么要从FactoryBean获取最终bean,可先忽略
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return (T) bean;
doGetBean的逻辑很清晰:
1.先从缓存获取bean,获取到则返回
getSingleton(beanName):
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
最终调用getSingleton(String beanName, boolean allowEarlyReference):
//一级缓存singletonObjects存放已经创建完毕的bean
//二级缓存earlySingletonObjects存在已经实例化,还没有属性注入和初始化完成的bean
//三级缓存singletonFactories存放的是创建bean的工厂
//三级缓存就是三个map
//private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//一级缓存获取不到并且当前bean正在创建则从二级缓存获取
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//二级缓存获取不到并且支持获取早期的bean则从三级缓存获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//从三级缓存获取工厂并创建bean,把创建的bean放入二级缓存并删除三级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
2 .获取不到就创建bean
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
下面的流程以先创建AService为前提,此时缓存中AService不存在,那么就会创建AService
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) {
//当前正在销毁bean则报异常
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到Set集合中记录当前bean正在创建:this.singletonsCurrentlyInCreation.add(beanName)
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//创建bean:调用createBean方法
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正在创建记录:
//this.singletonsCurrentlyInCreation.remove(beanName)
afterSingletonCreation(beanName);
}
if (newSingleton) {
//把bean放入一级缓存,并清除二,三级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
getSingleton(String beanName, ObjectFactory<?> singletonFactory)主要步骤:
2.1.从一级缓存获取bean,获取到则返回,否则往下执行
2.2.将beanName添加到singletonsCurrentlyInCreation表示当前bean正在创建
protected void beforeSingletonCreation(String beanName) {
//inCreationCheckExclusions保存的都是不需要检查的bean
//singletonsCurrentlyInCreation保存的都是当前正在创建的bean
//当前bean需要检查时,就添加singletonsCurrentlyInCreation
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
//当添加不成功时,说明当前bean正在创建现在又要创建,也就时发生了循环依赖才会这样
//这里发生循环依赖是直接报错的,实际上第一次创建时进行了缓存(三级缓存),发生循环依赖再次创建是直接取缓存的,不会走这里
throw new BeanCurrentlyInCreationException(beanName);
}
}
//当spring没有解决循环依赖时就会报这个错
public BeanCurrentlyInCreationException(String beanName) {
super(beanName,
"Requested bean is currently in creation: Is there an unresolvable circular reference?");
}
2.3.createBean
调用singletonFactory.getObject()创建bean,也就是createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法
createBean:
//只保留主要源码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
最终调用doCreateBean(beanName, mbdToUse, args)
doCreateBean:创建bean的核心逻辑,也就是bean的生命周期逻辑,能走到这里说明bean是第一次被创建,换句话说每个bean只会经历一次这个方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//实例化:通过反射实例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//当前bean是单例,并且正在创建中,并且容器支持循环依赖(默认是支持的)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//加入三级缓存:解决循环依赖和AOP同时发生情况的精妙之处
//这里只是允许循环依赖的发生但并不一定真正发生循环依赖,并且bean第一次创建并不知道后
//面会不会发生循环依赖,妙处就是它是一个函数,此处并不会真正执行,等待被调用就行了
//三级缓存只有循环依赖真正发生时才会被调用也就是执行getEarlyBeanReference方法,内
//部调用aop生成代理类
//什么时候被调用的呢?接着往下看
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
//属性注入:此处AService注入属性BService,会套娃执行getBean(beanName)创建BService
populateBean(beanName, mbd, instanceWrapper);
//初始化:1.执行初始化方法
//2.后置处理器方法:aop就是通过后置处理器完成的
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//重新获取bean,重新获取的bean可能是原始bean也可能是代理bean,具体情况后续说明
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
}
doCreateBean的过程:
2.3.1 实例化bean
2.3.2 添加当前bean的三级缓存
当前bean是单例,并且正在创建中,并且容器支持循环依赖时earlySingletonExposure=true,并且添加当前bean的三级缓存。
addSingletonFactory:
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);
}
}
}
getEarlyBeanReference方法:
//执行spring的扩展接口SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
//aop的基础类AbstractAutoProxyCreator就实现了该扩展接口,它的作用就是通过动态代理生成当前bean的代理类
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;
}
//AbstractAutoProxyCreator的实现
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
//如果需要生成代理则返回代理bean,否则返回原始bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
三级缓存本身是一个函数,只有调用的时候才会执行,这一步只是创建函数并没有执行,什么时执行的呢?接着往下
2.3.3.属性注入
循环依赖就是发生在此阶段,此时AService注入BService就会执行getBean(beanName)创建BService和创建AService一样的流程,至此bean的创建流程大概为:
创建AService --->添加三级缓存 --->注入BService --->创建BService ---> 添加三级缓存 ---> 注入AService --->创建AService
此时发生循环依赖再次创建AService,先从缓存获取AService的实例,因为AService的三级缓存在第一次创建AService的步骤2.3.2已经存入,再次创建就会通过三级缓存获取bean也就是调用函数getEarlyBeanReference获取AService,这样BService的属性注入完成,最终AService注入BService完成属性注入
在第一次创建AService时其实并不知道会发生循环依赖,只有属性注入阶段才会发现,当然循环依赖也不会一定发生,三级缓存只在发生循环依赖时才会被执行。
2.3.4.初始化
看下initializeBean初始化的过程:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//执行后置处理器BeanPostProcessor的postProcessBeforeInitialization
//其中就包含执行@PostConstruct初始化方法的处理器CommonAnnotationBeanPostProcessor
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//执行初始化方法InitializingBean的afterPropertiesSet方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//执行后置处理器BeanPostProcessor的postProcessAfterInitialization方法
//也是aop生成代理类的地方,AbstractAutoProxyCreator的postProcessAfterInitialization方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
2.3.5.重新获取bean
这里会有几种情况:
1.earlySingletonExposure=true,允许循环依赖并且确实发生了循环依赖 调用getSingleton(beanName, false)具体查看步骤1调用getSingleton(String beanName, boolean allowEarlyReference),因为循环依赖已经发生,也就 是 AService的三级缓存已经执行(获取的bean会放入二级缓存),那么此 时取到的就是二级缓存的bean(原始bean或代理bean具体看bean本身是否 需要代理)
2.earlySingletonExposure=true,允许循环依赖但没有发生循环依赖
调用getSingleton(beanName, false)具体查看步骤1调用getSingleton(String beanName, boolean allowEarlyReference),因为循环依赖没发生,此时二级 缓存是空的,那么返回的就是正常流程初始化完成的exposedObject,具体看 2.3.4中applyBeanPostProcessorsAfterInitialization调用后置处理器的方法, 返回的是原始bean或代理bean(具体看bean本身是否需要代理)
3.earlySingletonExposure=false,不支持循环依赖
那么返回的就是正常流程初始化完成的exposedObject,具体看 2.3.4中 applyBeanPostProcessorsAfterInitialization调用后置处理器的方法, 返回的是原始bean或代理bean(具体看bean本身是否需要代理)
生成aop的地方有个问题,循环依赖和aop同时发生时,创建AService的过程中属性注入和初始化都会生成代理类,那不是重复生成代理类了?
再看下AbstractAutoProxyCreator的postProcessAfterInitialization方法 和getEarlyBeanReference方法
//AbstractAutoProxyCreator的getEarlyBeanReference方法
public Object getEarlyBeanReference(Object bean, String beanName) {
//key:就是beanName 或(如果是FactoryBean就是&加beanName)
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//发生循环依赖通过三级缓存执行该方法
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
//AbstractAutoProxyCreator的postProcessAfterInitialization方法
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//不相等说明是空,没发生循环依赖,那么就去生成
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
其实aop就发生在两个地方最终都是通过AbstractAutoProxyCreator生成的:
1.发生循环依赖时,在属性注入阶段通过调用三级缓存来触发aop(调用getEarlyBeanReference)
2. 在初始化完成后通过调用后置处理器触发aop(调用postProcessAfterInitialization)
属性注入在初始化之前,所以对于同一个bean,getEarlyBeanReference是优先于postProcessAfterInitialization执行的,所以通过 earlyProxyReferences缓存来判断避免了重复生成代理类,二者只会有一处真正进行aop
2.4.移除当前bean正在创建的标记
从singletonsCurrentlyInCreation中移除当前beanName
2.5.将单例bean放入缓存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//放入一级缓存,说明此时创建的bean是初始化完成的bean,可以正常使用了
this.singletonObjects.put(beanName, singletonObject);
//删除三级缓存,什么时候存进去的接着往下看createBean
this.singletonFactories.remove(beanName);
//删除二级缓存,什么时候存进去的接着往下看createBean
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
至此bean就创建完毕了
三.总结
现在总结下为什么使用三级缓存解决循环依赖
其实解决循环依赖只用二级缓存就能解决,根本思路就是把未初始化完成的bean放入二级缓存earlySingletonObjects提前暴露,甚至不考虑安全性单单从解决循环依赖的角度出发,只使用一级缓存singletonObjects就能解决,不过未初始化完成的bean被使用有可能造成安全问题。
那为什么使用三级缓存呢?假设现在只有两级缓存,那么就需要在属性注入前就要生成代理类,也就是在AService实例化阶段就生成代理类放入二级缓存earlySingletonObjects,这样确实也能解决循环依赖的问题。但是当循环依赖和aop同时发生时,但是这就破坏了bean的生命周期(而且在没有发生循环依赖时没必要这么做),正常aop发生在初始化之后,但是现在提前到了实例化阶段,实例化阶段还要处理生成代理类的逻辑,这样生命周期的过程就耦合了。使用三级缓存通过函数的形式使aop延迟要属性注入阶段,同时尽最大程度保持生命周期每一步逻辑的解耦。