Spring循环依赖源码解析
概念区分
- 实例化(instantiation):创建了一个对象,容器通过反射的方式new了一个对象
- 初始化(initialization):已经实例化的对象,并完成属性的填充,即
初始化 = 实例化 + 属性填充
。实例化后的对象就可以直接使用了 - 提前暴露(early exposure):主要用于解决循环依赖的问题,通过ObjectFactory的方式保存产生Bean的方式,为后续获取Bean提供访问方式
Spring容器初始化Bean的基本流程
核心源码:AbstractAutowireCapableBeanFactory#doCreateBean
- 实例化:创建一个Bean对象
- 属性填充:为Bean设置属性值和依赖
- 为了解决循环依赖的问题,Spring会通过提前暴露Bean的方式,提供还未完成初始化的Bean的访问方式
- 初始化:初始化阶段涉及的步骤较多
- 检查
Aware
接口,调用setXxx()
注入特定的依赖 - 调用
BeanPostProcessor
的前置处理方法ApplicationContextAwareProcessor
注入ApplicationContextAware
相关的依赖InitDestroyAnnotationBeanPostProcessor
调用@PostConstruct
注释的初始化方法
InitializingBean.afterPropertiesSet()
- XML中的
init-method
- 调用
BeanPostProcessor
的后置处理方法
- 检查
- 注册销毁相关的回调接口 ,创建
DisposableBeanAdapter
对象- 注册
DisposableBean.destroy()
接口 - 注册XML中配置的
destroy-method
@PreDestroy
对应InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction()
- 注册
- 使用Bean
- 调用销毁方法,
DisposableBeanAdapter.destroy()
三级缓存解决循环依赖的核心源码
因为仅关心Spring解决循环依赖的核心源码,其它源码部分省略:
- 属性注入的核心源码:
AutowiredAnnotationBeanPostProcessor
- 产生动态代理的核心源码:
AnnotationAwareAspectJAutoProxyCreator
DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)
继承关系:DefaultSingletonBeanRegistry <- AbstractBeanFactory <- AbstractAutowireCapableBeanFactory
// DefaultSingletonBeanRegistry
/** 用于存储已经初始化完毕的Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 用于存储Bean对应的ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 用于存储已经实例化,属性未填充的Bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 将初始化完毕的Bean加入singletonObjects,并从singletonFactories和earlySingletonObjects中移除
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);
}
}
(\*\*)
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从singletonObjects获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
//Bean未初始化完成,且Bean还在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从earlySingletonObjects中获取Bean
singletonObject = this.earlySingletonObjects.get(beanName);
// 未获取到Bean,且allowEarlyReference == true
if (singletonObject == null && allowEarlyReference) {
// 从singletonFactories获取Bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 获取Bean
singletonObject = singletonFactory.getObject();
// 将Bean放置到earlySingletonObjects
this.earlySingletonObjects.put(beanName, singletonObject);
// 从singletonFactories中移除Bean
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
//核心就是调用singletonFactory获取Bean
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
//先从singletonObjects中取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// ......
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// ......
}
catch (BeanCreationException ex) {
// ......
}
finally {
// ......
}
if (newSingleton) {
// 将生成的Bean添加到singletonObjects中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
// 将beanName和对应的singletonFactory存入singletonFactories
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 如果beanName在singletonObjects没有已经初始化完成的Bean,就保存singletonFactory到singletonFactories
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName); //从earlySingletonObjects中移除Bean
this.registeredSingletons.add(beanName); //表示Bean已经注册
}
}
}
AbstractBeanFactory#doGetBean
// AbstractBeanFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 先从三级缓存的Map中获取数据
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//......
}
else {
//......
try {
//Bean不在缓存中
// 创建单例的Bean实例
if (mbd.isSingleton()) {
// 实际上就是调用createBean获取Bean
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//......
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 创建prototype的Bean实例
// ......
}
else {
//其他scope的处理逻辑
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// ......
return (T) bean;
}
getSingleton(String beanName, boolean allowEarlyReference)
:从三级缓存中获取BeangetSingleton(String beanName, ObjectFactory<?> singletonFactory)
:调用createBean()
创建Bean,并添加到singletonObjects
AbstractAutowireCapableBeanFactory#doCreateBean
//AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//创建Bean实例
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final 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) {
// (\*\*) 将beanName对应的ObjectFactory存入singletonFactories,再次获取Bean时,直接从singletonFactories中获取
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//填充@Autowired属性
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
//.......
}
// 解决代理对象的依赖问题
if (earlySingletonExposure) {
//如果Bean被AOP代理,这里就会从earlySingletonObjects中获取到代理对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// earlySingletonReference -> exposedObject
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// .....
}
}
}
//......
return exposedObject;
}
//用于解决循环依赖的场景,返回bean
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
// 获取要返回的对象
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// SmartInstantiationAwareBeanPostProcessor获取早期的Bean
// AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference会返回代理对象
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
无AOP循环依赖解决示例
以循环依赖的示例串联整个过程:
@Component
public class Teacher {
@Autowired
Student student;
public Teacher() {
System.out.println("Teacher init:" + student);
}
}
@Component
public class Student {
@Autowired
Teacher teacher;
public Student() {
System.out.println("Student init:" + teacher);
}
}
以容器先创建Student,再创建Teacher为例。为了简化分析过程,仅围绕和循环依赖的内容展开:
- 获取Student实例:
AbstractBeanFactory#getBean(String) -> AbstractBeanFactory#doGetBean
- 因为容器中目前没有Student实例,创建Student实例:
instanceWrapper = createBeanInstance(beanName, mbd, args);
- 因为容器中目前没有Student实例,创建Student实例:
- 提前暴露Student实例:
- 计算是否需要提前暴露Bean实例:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
DefaultSingletonBeanRegistry#addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
:将beanName==student
的() -> getEarlyBeanReference(beanName, mbd, bean)
的ObjectFactory
添加到singletonFactories
中
- 计算是否需要提前暴露Bean实例:
- Student实例属性填充:
AbstractAutowireCapableBeanFactory#populateBean
- 获取Teacher实例:
DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)
- 因为容器中目前没有Teacher实例,创建Teacher实例:
instanceWrapper = createBeanInstance(beanName, mbd, args);
- 因为容器中目前没有Teacher实例,创建Teacher实例:
- 提前暴露Teacher实例
- 计算是否需要提前暴露Bean实例:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
DefaultSingletonBeanRegistry#addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
:将beanName==teacher
的() -> getEarlyBeanReference(beanName, mbd, bean)
的ObjectFactory添加到singletonFactories中;
- 计算是否需要提前暴露Bean实例:
- Teacher实例属性填充:
AbstractAutowireCapableBeanFactory#populateBean
- 获取Student实例:
AbstractBeanFactory#getBean(String) -> AbstractBeanFactory#doGetBean
- 因为singletonFactories中已有Student实例,直接获取到Student实例:(**)DefaultSingletonBeanRegistry#getSingleton(String) -> DefaultSingletonBeanRegistry#getSingleton(String, true):
- 此时
allowEarlyReference==true
,且仅有singletonFactories
中保存了student对应的ObjectFactory,所以会调用singletonFacotry.getObject()
获取Student实例, - 而这实际通过匿名内部类的方式调用了
() -> getEarlyBeanReference(beanName, mbd, bean)
,获取到对应的Student的实例对象。(注意这里的Student对象还没有Teacher属性,即还未完成属性填充) - (**)获取的Student实例后,被放置到
earlySingletonObjects
中,并且从singletonFactories
中移除student的ObjectFactory;
- 此时
- 因为singletonFactories中已有Student实例,直接获取到Student实例:(**)DefaultSingletonBeanRegistry#getSingleton(String) -> DefaultSingletonBeanRegistry#getSingleton(String, true):
- Teacher完成属性填充
- 因为
earlySingletonExposure==true
,Teacher实例暴露的后续逻辑:- 执行
DefaultSingletonBeanRegistry#getSingleton(String, boolean)
:因为allowEarlyReference == false
,执行完逻辑,返回一个null - 因为earlySingletonReference==null,不会替换初始化完毕的Teacher的实例
- 执行
- Teacher实例初始化完成
- Student实例完成属性填充
- 因为
earlySingletonExposure == true
,Student实例暴露的后续逻辑:- 这时
earlySingletonObjects
已经保存了student的对象,所以直接返回 - 执行
exposedObject = earlySingletonReference
,此时exposedObject和earlySingletonReference本来就是一个对象,所以不影响
- 这时
- Student实例完成初始化
第7步,Teacher完成属性填充后,Student还未填充属性:
第11步,Student完成属性填充
有AOP循环依赖解决示例
现在为Student#learn()
添加一个切面
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* com.ldh.circular.dependency.entity.Student.learn(..))")
public void pointcut() {
}
@Before("pointcut()")
public void beforeAdvice(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
System.out.println(String.format("在方法:%s之前,前置前面逻辑", signature.getName()));
}
}
- 获取Student实例:
AbstractBeanFactory#getBean(String) -> AbstractBeanFactory#doGetBean
- 因为容器中目前没有Student实例,创建Student实例:
instanceWrapper = createBeanInstance(beanName, mbd, args);
。注意:这里仅返回了Student的单例,并不是代理对象
- 因为容器中目前没有Student实例,创建Student实例:
- 提前暴露Student实例:
- 计算是否需要提前暴露Bean实例:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
DefaultSingletonBeanRegistry#addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
:将beanName==student
的() -> getEarlyBeanReference(beanName, mbd, bean)
的ObjectFactory
添加到singletonFactories
中
- 计算是否需要提前暴露Bean实例:
- Student实例属性填充:
AbstractAutowireCapableBeanFactory#populateBean
- 获取Teacher实例:
DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)
- 因为容器中目前没有Teacher实例,创建Teacher实例:
instanceWrapper = createBeanInstance(beanName, mbd, args);
- 因为容器中目前没有Teacher实例,创建Teacher实例:
- 提前暴露Teacher实例
- 计算是否需要提前暴露Bean实例:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
DefaultSingletonBeanRegistry#addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
:将beanName==teacher
的() -> getEarlyBeanReference(beanName, mbd, bean)
的ObjectFactory添加到singletonFactories中;
- 计算是否需要提前暴露Bean实例:
- Teacher实例属性填充:
AbstractAutowireCapableBeanFactory#populateBean
- 获取Student实例:
AbstractBeanFactory#getBean(String) -> AbstractBeanFactory#doGetBean
- 因为singletonFactories中已有Student实例,直接获取到Student实例:(**)DefaultSingletonBeanRegistry#getSingleton(String) -> DefaultSingletonBeanRegistry#getSingleton(String, true):
- 此时
allowEarlyReference==true
,且仅有singletonFactories
中保存了student对应的ObjectFactory,所以会调用singletonFacotry.getObject()
获取Student实例, - (**)而这实际通过匿名内部类的方式调用了
() -> getEarlyBeanReference(beanName, mbd, bean)
,获取到对应的Student的代理对象。(注意这里的Student代理对象还没有Teacher属性,即还未完成属性填充) - (**)获取的Student的代理对象后,被放置到
earlySingletonObjects
中,并且从singletonFactories
中移除student的ObjectFactory;
- 此时
- 因为singletonFactories中已有Student实例,直接获取到Student实例:(**)DefaultSingletonBeanRegistry#getSingleton(String) -> DefaultSingletonBeanRegistry#getSingleton(String, true):
- Teacher完成属性填充
- 因为
earlySingletonExposure==true
,Teacher实例暴露的后续逻辑:- 执行
DefaultSingletonBeanRegistry#getSingleton(String, boolean)
:因为allowEarlyReference == false
,执行完逻辑,返回一个null - 因为earlySingletonReference==null,不会替换初始化完毕的Teacher的实例
- 执行
- Teacher实例初始化完成
- Student实例完成属性填充
- 因为
earlySingletonExposure == true
,Student实例暴露的后续逻辑:- 这时
earlySingletonObjects
已经保存了Student的代理对象,所以直接返回 - 执行
exposedObject = earlySingletonReference
,此时Student的代理对象设置成exposedObject
- 这时
- Student实例完成初始化
执行完第1步,Student实例并不是一个代理对象:
执行完7.2步,已经生成Student的代理对象:
执行完第8步,看以看到,Teacher实例已经注入了Student的代理对象:
执行完第11步,Student实例完成属性填充后如下所示,可以看到Teacher中注入的已经是代理对象,而Student实例并不是被代理。
有无AOP的区别
有无AOP的区别在于是否会执行AnnotationAwareAspectJAutoProxyCreator#getEarlyBeanReference
生成Bean的动态代理对象,其它的流程基本是一致的。
为什么是三级缓存而不是二级缓存?
实际上如果不考虑动态代理的情况下,只要将未完成初始化的实例保存到一个缓存,然后,在需要注入Bean的时候,直接注入即可。
但是,因为要支持动态代理,且Spring一开始实例化对象时,并不会直接返回一个代理对象(PS:目前我也不清楚原因~~~)。因此,没法提前暴露一个未代理的对象到一个缓存中,Spring采用ObjectFactory的形式暴露了Bean的访问方式。后续,需要注入这个Bean时,Spring通过ObjectFactory#getObject()
的方式获取到所需的Bean(如果Bean加了动态代理,内部会通过AnnotationAwareAspectJAutoProxyCreator#getEarlyBeanReference
的方式获取代理对象)。所以,Spring需要提供三级缓存:
- singletonObjects:保存已经初始化完毕的Bean
- singletonFactories:保存需要提前暴露,但是目前没法直接返回的Bean,通过ObjectFactory的形式封装
- earlySingletonObjects:保存通过
ObjectFactory#getObject()
获取的Bean
参考:
posted on 2022-11-06 21:13 DaydayupLiu 阅读(269) 评论(0) 编辑 收藏 举报
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战