总结
前言
接着上篇Spring IOC 源码一,本篇接着讲springioc 中循环依赖是如何处理的。
1.循环依赖产生的条件
大家应该有看过《盗梦空间》吧,梦与梦之间相互关联,梦与现实相互交替让整个故事扑朔迷离。如果最后小李子不认为她的老婆是虚拟的,那么他就会永远走不出梦境。
Bean的创建主要过程:实例化,属性注入,初始化
-
先创建DreamOne,实例化DreamOne,此时DreamOne中的属性dreamTwo为空,填充属性dreamTwo;
-
从ioc容器中查找DreamTwo中,DreamTwo并未创建,开始创建DreamTwo;
-
实例化DreamTwo,此时DreamTwo中的属性dreamOne为空,填充dreamOne;
-
从ioc容器中查找DreamOne,未找到,接着创建DreamOne.
这样就形成了闭环。
1.1 解决思路
仔细再看上面的流程,会发现DreamOne其实是存在的,只不过DreamOne还不是一个完整的对象,只是完成了实例化还未初始化。如果在程序调用过程中,拥有了 某个对象的引用,后期再给他完成赋值操作,相当于提前暴露了某个不完整对象的引用,这样就能够提前打破闭环。
spring就是这样,提前暴露了对象的引用,将实例化和初始化分开操作。这样就解决了循环依赖。
2.循环依赖的解决
在Spring IOC 源码一中有介绍,在实例化bean后,属性注入之前,将bean放入了三级缓存singletonFactories,此时添加的是一个函数式接口。目的是保证在整个容器运行的过程中同名的bean对象只有一个。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
BeanWrapper instanceWrapper = null;
// 单例模型,则从未完成的 FactoryBean 缓存中删除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// ❶使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装的实例对象
final Object bean = instanceWrapper.getWrappedInstance();
// 包装的实例对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//❷ 如果有后置处理,则允许后置处理修改 BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// applyMergedBeanDefinitionPostProcessors
//调用属性合并后置处理器, 进行属性合并
//这里会进行 一些注解 的扫描
//CommonAnnotationBeanPostProcessor -> @PostConstruct @PreDestroy @Resource
//AutowiredAnnotationBeanPostProcessor -> @Autowired @Value
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
mbd.postProcessed = true;
}
}
// ❸解决单例模式的循环依赖
// 单例模式 & 运行循环依赖&当前单例 bean 是否正在被创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 提前将创建的 bean 实例加入到三级缓存singletonFactories中
// 这里是为了后期避免循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
//❹对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
// 则会递归初始依赖 bean
populateBean(beanName, mbd, instanceWrapper);
//❺调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
/**
* ❻循环依赖处理
* Spring 循环依赖的场景有两种:
* 构造器的循环依赖
* field 属性的循环依赖
* 对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖
*/
if (earlySingletonExposure) {
// 获取 earlySingletonReference
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
if (earlySingletonReference != null) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
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);
}
}
}
}
}
// Register bean as disposable.
try {
// 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
2.1 三级缓存
普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象。
在实际的调用过程中,是没有办法确定什么时候对象被使用,所以就要求当某个对象被调用的时候,优先判断此对象是否需要被代理(一文弄懂AOP源码),类似于一种回调机制的实现,因此传入lambda表达式的时候,可以通过lambda表达式来执行对象的覆盖过程,getEarlyBeanReference()
2.2 属性注入
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
/**
* 在设置属性之前给 InstantiationAwareBeanPostProcessors 最后一次改变 bean 的机会
*/
boolean continueWithPropertyPopulation = true;
// 是否持有 InstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 如果后续处理器发出停止填充命令,则终止后续操作
if (!continueWithPropertyPopulation) {
return;
}
// bean 的属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 根据Bean配置的自动装配模式完成注入,默认是0,即不走以下逻辑
// 如果设置了相关的依赖装配方式,会遍历Bean中的属性
// 根据类型或名称来完成相应注入,无需额外配置
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
// 将 PropertyValues 封装成 MutablePropertyValues 对象
// MutablePropertyValues 允许对属性进行简单的操作,
// 并提供构造函数以支持Map的深度复制和构造。
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根据名称自动注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 根据类型自动注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 是否已经注册了 InstantiationAwareBeanPostProcessors
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 从 bw 对象中提取 PropertyDescriptor 结果集
// PropertyDescriptor:可以通过一对存取方法提取一个属性
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 对所有需要依赖检查的属性进行后处理
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//❶调用AutowiredAnnotationBeanPostProcessor来完成属性的赋值
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
// 依赖检查,对应 depends-on 属性
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 将属性应用到 bean 中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
❶处调用AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法完成属性的赋值@Autowired原理
最终会调用
#DefaultListableBeanFactory.class
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
//❶判断注入的bean是否需要懒加载,
//这里是spring解决构造函数循环依赖的处理逻辑
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
//❷ 如果没有标注@Lazy,则执行真正创建bean的过程
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
❶getLazyResolutionProxyIfNecessary
如果有标注@Lazy,则生成代理,详见@Autowired原理
❷doResolveDependency
如果没有懒加载,则进行真正创建Bean的过程。
再回到AbstractBeanFactory#doGetBean方法创建DreamTwo
后面创建DreamTwo和DreamOne类似,在实例化DreamTwo对象后,将函数式接口添加到三级缓存,再接着进入属性注入DreamOne.
2.3 循环依赖
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//❶
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//❷
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**
* containsBeanDefinition 中存在 beanName 相对应的 BeanDefinition
*/
try {
/**
* 合并父类相关属性
*/
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
/**
* 获取依赖。
* 在初始化 bean 时解析 depends-on 标签时设置
*/
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 迭代依赖
for (String dep : dependsOn) {
// 检验依赖的bean 是否已经注册给当前 bean
// 获取其他传递依赖bean
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//没有注册到依赖bean中
// 注册到依赖bean中
registerDependentBean(dep, beanName);
try {
// 调用 getBean 初始化依赖bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
//❸
sharedInstance = getSingleton(beanName, () -> {
try {
/**
* beanName:bean 的名字
* mbd:已经合并了父类属性的(如果有的话)BeanDefinition
* args:用于构造函数或者工厂方法创建 bean 实例对象的参数
*/
//❹
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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return (T) bean;
}
直接看第二步getSingleton方法
#DefaultSingletonBeanRegistry.class
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//❶
Object singletonObject = this.singletonObjects.get(beanName);
// ❷缓存中的 bean 为空,且当前 bean 正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//加锁保证 二级缓存添加和三级缓存删除操作的原子性,同时二级缓存和三级缓存就没有必要用concurrentHashMap了
synchronized (this.singletonObjects) {
//❸ 从 earlySingletonObjects 获取
singletonObject = this.earlySingletonObjects.get(beanName);
// earlySingletonObjects 中没有,且允许提前创建
if (singletonObject == null && allowEarlyReference) {
// ❹从 singletonFactories 中获取对应的 ObjectFactory
/**
* allowEarlyReference:从字面意思上面理解就是允许提前拿到引用。
* 其实真正的意思是是否允许从 singletonFactories 缓存中通过 getObject() 拿到对象,为什么会有这样一个字段呢?
* 原因就在于 singletonFactories 才是 Spring 解决 singleton bean 的诀窍所在
*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// ObjectFactory 不为空,则创建 bean
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();//类似回调覆盖 执行lambda 表达式 AOP
//❺添加到二级缓存,同时从三级缓存中删除
this.earlySingletonObjects.put(beanName, singletonObject);//三级缓存升到二级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
❷.此时判断条件isSingletonCurrentlyInCreation是真
因为在创建Bean之前beforeSingletonCreation方法将bean添加到了singletonsCurrentlyInCreation集合中;Spring IOC 源码一(详见2.2)
getEarlyBeanReference方法。
从三级缓存singletonFactories中获取到DreamOne后,DreamTwo可以顺利的继续执行属性注入过程了。紧接着开始实例化DreamTwo,该过程省略,详细过程请参考Spring IOC 源码一
当DreamTwo完成实例化后,会再次调用 getSingleton(beanName, false)
#AbstractAutowireCapableBeanFactory.class#doCreateBean
if (earlySingletonExposure) {
// 获取 earlySingletonReference
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
if (earlySingletonReference != null) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
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);
}
}
}
}
这次传入的allowEarlyReference是false,因为dreamTwo已经实例化完成,所以不需要提前暴露
#DefaultSingletonBeanRegistry.class
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//❶
Object singletonObject = this.singletonObjects.get(beanName);
// 缓存中的 bean 为空,且当前 bean 正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//加锁保证 二级缓存添加和三级缓存删除操作的原子性,同时二级缓存和三级缓存就没有必要用concurrentHashMap了
synchronized (this.singletonObjects) {
//❷ 从 earlySingletonObjects 获取
singletonObject = this.earlySingletonObjects.get(beanName);
// earlySingletonObjects 中没有,且允许提前创建
if (singletonObject == null && allowEarlyReference) {
// ❸从 singletonFactories 中获取对应的 ObjectFactory
/**
* allowEarlyReference:从字面意思上面理解就是允许提前拿到引用。
* 其实真正的意思是是否允许从 singletonFactories 缓存中通过 getObject() 拿到对象,为什么会有这样一个字段呢?
* 原因就在于 singletonFactories 才是 Spring 解决 singleton bean 的诀窍所在
*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// ObjectFactory 不为空,则创建 bean
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();//类似回调覆盖 执行lambda 表达式 AOP
this.earlySingletonObjects.put(beanName, singletonObject);//三级缓存升到二级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
此时,二级缓存earlySingletonObjects中有DreamOne对象,三级缓存singletonFactories中有DreamTwo对象。当从二级缓存中没有找到DreamTwo时,因为allowEarlyReference是false,所以不会再从三级缓存中获取DreamTwo。 最后创建出来的DreamTwo对象是
DreamTwo创建成功后,回到创建Bean时函数回调地方。
#DefaultSingletonBeanRegistry.class
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//全局加锁
synchronized (this.singletonObjects) {
// 从缓存中检查一遍
//因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查
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!)");
}
//加载前置处理,将bean的状态修改为正在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 初始化 bean
// 这个过程其实是调用 createBean() 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//❶后置处理,将bean的状态从正在创建中移除
afterSingletonCreation(beanName);
}
// 加入缓存中
if (newSingleton) {
/**
* ❷一级缓存添加
*/
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
❶afterSingletonCreation
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}从正在创建的单例bean集合singletonsCurrentlyInCreation中removed掉DreamTwo。(在第一次调用getSingleton从三级缓存singletonFactories中获取bean时,会做为判断条件)。
❷addSingleton
将创建好的DreamTwo对象添加到一级缓存中。
#DefaultSingletonBeanRegistry.class
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);
}
}
此时,二级缓存earlySingletonObjects中有DreamOne对象,三级缓存singletonFactories中有DreamTwo对象 所以会将DreamTwo从三级缓存singletonFactories中删掉,将经过ioc完整的DreamTwo对象添加到一级缓存singletonObjects中。
完成DreamTwo的创建后,再回到DreamOne的属性注入部分,设置DreamTwo的value值。后续步骤基本很类似,省略。到这里spring的循环依赖就解决了。
3.总结
三级缓存是否都需要?
首先回顾一下三级缓存分别的创建销毁时间
三级缓存:createBeanInstance之后:addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存getSingleton
一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingleton
从上诉分析中可以分析出,spring解决循环依赖的关键是 实例化和初始化分开操作。
将bean的几种状态:完成实例化,但未完成初始化;是否需要代理;完整状态通过不同的HashMap存储。所以便有了三级缓存。
3.1 如果没有三级缓存
如果没有三级存储, Spring 选择二级缓存来解决循环依赖的话,那么就意味着所有Bean都需要在实例化完成之后就立马判断是否需要生成代理对象。而Spring的设计原则是在Bean初始化完成之后才为其创建代理。
因为aop的原理是实现了SmartInstantiationAwareBeanPostProcessor的后置处理方法postProcessAfterInitialization来创建代理对象。详见Spring IOC 源码一。
如果提前创建代理,则有违背spring的设计原则;因为循环依赖的出现,如果不创建代理,后面就没有机会再创建代理对象,注入的就是原始对象,也会产生错误。
还有另外一个方面的角度解析,详见一文弄懂AOP源码,站在的立场不一样,基于代理的代码优化角度来看的,这是我个人的一种看法,欢迎指正。
3.2 springBoot高版本循环依赖报错问题
Springboot2.6之后的版本,默认把循环依赖给禁用了。如果项目中存在循环依赖,需要添加一行配置
spring.main.allow-circular-references=true
否则会启动报错,说明Spring是不太赞成我们用循环依赖的。当有循环依赖产生的时候,这时候我们需要检查一下我们设计可能出了问题。
关注我的你,是最香哒!
原文始发于微信公众号(小李的源码图):一文弄懂Spring的循环依赖是如何解决的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/145405.html