查看原文:spring5.x-解决循环依赖分析
目录
什么是循环依赖?
当对象嵌套对象多层的时候,为什么不会造成死循环?还是通过如何特殊处理?
代码实现
package com.hong.model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @ClassName OrderInfo
* @Description 订单bean
* @Author csh
* @Date 2023/2/17 17:19
*/
@Component
public class OrderInfo{
//订单号
private String orderNo;
//支付状态
private String payStatus;
//用户信息
private User userInfo;
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getPayStatus() {
return payStatus;
}
public void setPayStatus(String payStatus) {
this.payStatus = payStatus;
}
public User getUserInfo() {
return userInfo;
}
public void setUserInfo(User userInfo) {
this.userInfo = userInfo;
}
public OrderInfo() {
System.out.println("订单正在初始化...");
this.orderNo = "123456";
}
@Override
public String toString() {
return "OrderInfo{" +
"orderNo='" + orderNo + '\'' +
", payStatus='" + payStatus + '\'' +
", userInfo=" + userInfo +
'}';
}
}
package com.hong.model;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @ClassName User
* @Description 用户
* @Author csh
* @Date 2023/1/13 14:27
*/
@Component
public class User{
private String userName;
private int age;
private String nickName;
private OrderInfo orderInfo;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public User() {
System.out.println("用户正在初始化...");
this.userName = "hong";
}
public OrderInfo getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(OrderInfo orderInfo) {
this.orderInfo = orderInfo;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
", nickName='" + nickName + '\'' +
", orderInfo=" + orderInfo +
'}';
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext((TestMain.class));
OrderInfo orderInfo = applicationContext.getBean(OrderInfo.class);
System.out.println(orderInfo.toString());
User user = applicationContext.getBean(User.class);
System.out.println(user.toString());
}
spring仅解决了哪些循环依赖?
位置 | 是否解决 | |
属性setter注入 | 是 | |
属性自动注入 | 是 | 比如:@Autowired |
构造器自动注入 | 是 | |
构造器循环依赖另一个对象 | 否 | A构造器依赖另一个构造器 |
spring三级缓存
缓存名称 | 描述 | 备注 |
singletonObjects | 该缓存存放已经创建完成的Bean实例,也就是单例模式的Bean。在Bean创建完成后,将Bean实例放入该缓存中。 | 一级 |
earlySingletonObjects | 该缓存存放创建中的Bean实例,也就是Bean正在创建时,处于实例化和依赖注入阶段的Bean。在Bean创建时,将Bean实例放入该缓存中,以便解决循环依赖问题。 | 二级 |
singletonFactories | 该缓存存放创建中的Bean实例工厂,也就是用于创建Bean实例的工厂对象。在Bean创建时,如果该Bean需要被代理,则会将该Bean的代理工厂对象放入该缓存中。 | 三级 |
三级缓存的作用是为了保证Bean的创建过程中的线程安全性和循环依赖的解决。其中,singletonObjects缓存中的Bean实例是线程安全的,而earlySingletonObjects和singletonFactories缓存中的Bean实例是线程不安全的,需要通过同步机制来保证线程安全性。同时,earlySingletonObjects和singletonFactories缓存也是解决循环依赖问题的关键。当两个Bean之间存在循环依赖时,通过从缓存中获取Bean实例,可以避免循环依赖导致的死循环问题。
源码学习
初始化bean
spring在初始化的时候进入refresh()中的finishBeanFactoryInitialization会将剩余非懒加载的bean进行实例化其中包括该对象依赖的属性。具体跟进如下。
org.springframework.context.support.AbstractApplicationContext#refresh中的
...
//实例化所有剩余的(非lazy-init)单例。
finishBeanFactoryInitialization(beanFactory);
...
然后进入到上下文的 Bean 工厂的初始化,初始化所有剩余的单例 Bean其中的preInstantiateSingletons会对属性进行实例化
// 实例化所有剩余(非懒加载初始化)单例
beanFactory.preInstantiateSingletons();
@Override
public void preInstantiateSingletons() throws BeansException {
...
//获取bean
getBean(beanName);
...
}
调用了doGetBean方法获取bean实例
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean调用getSingleton从缓存中获取,但是这里首次进来其实获取是空的。
那么会判断mbd.isSingleton() 是否为单例,如果进调用 getSingleton..进行创建bean。
/**
* 返回指定 Bean 的实例,该实例可以是共享的或独立的。
* @param name 要检索的 Bean 的名称
* @param requiredType 类型
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return Bean 的实例
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//获取bean名称
final String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取实例(核心方法****)
Object sharedInstance = getSingleton(beanName);
...
// 判断是否单例模式
if (mbd.isSingleton()) {
//获取实例
sharedInstance = getSingleton(beanName, () -> {
try {
//创建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);
}
//判断是否为原型
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
...
return (T) bean;
}
doCreateBean这里面主要做几件事,
-
创建bean :createBeanInstance
-
放到缓存中:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
-
填充属性:populateBean(beanName, mbd, instanceWrapper); 在这里解决了属性依赖的问题。
-
最后返回:exposedObject
/**
* 预处理创建指定的bean。这里就是三级缓存中其中初始化属性的实现。
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 实例化bean
BeanWrapper instanceWrapper = null;
//单例判断
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建单例bean并以BeanWrapper返回。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 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));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//添加到singletonFactories工厂缓存中
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);
}
}
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.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
/**
* 填充属性
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param bw the BeanWrapper with bean instance
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
...
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//获取属性注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
...
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
//下面的逻辑是获取属性对应的注入 beanFactory.isTypeMatch 内部调用了getSingleton
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
...
通过检查具有给定名称的Bean是否与指定的类型匹配。
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// 获取缓存值
Object beanInstance = getSingleton(beanName, false);
....
}
到此spring会根据对象的属性递归去调用getSingleton,如果不存在则进行创建,整个流程是循环调用的。
获取bean
然后再获取的bean其实已经实例化过了。
获取bean的方法
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
核心代码:用于解析Bean,ResolvableType.forRawClass(requiredType)用于获取requiredType的ResolvableType对象,args是构造函数的参数,false表示不允许Bean循环依赖
@Override
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
/** 核心代码:用于解析Bean,ResolvableType.forRawClass(requiredType)用于获取requiredType的ResolvableType对象,args是构造函数的参数,false表示不允许Bean循环依赖 **/
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
...
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
//通过三级缓存获取
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
...
/** 三级缓存的核心获取方法 先从一级缓存(singletonObjects)获取 ,
* 如果为空且不是正在创建中
* 同步锁方式 从二级缓存(earlySingletonObjects)获取
* 二级缓存获取为空且提供加载标识为真
* 通过单例工厂进行获取(singletonFactories) 且不为空 则进行初始化放到一二级缓存中
*
*
* 返回获取结果
*/
@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;
}
为什么要有三级缓存?
从源码中初始化属性依赖二级缓存(earlySingletonObjects)进行实现,那么三级缓存(singletonFactories),主要解决类似AOP中代理需要提前将代理的对象存缓存中,而被代理的对象仅需将代理的工厂放到三级缓存中而不需要进行实例化,所以这里三级缓存存的是代理工厂,而非实例化后的对象,仅需对象在需要调用时才进行实例化(从一二级中拿),所以这个设计也是比较合理,一级直接就是实例,二级缓存解决对象属性注入这个时候的对象并非完整,三级则存放代理的指引,而不是具体实现,其实到这里最终是通过这个代理签明回调的获取结果,各层分工明确,也比较好理解。
个人理解:工厂的g成品(一级缓存) 半成品(二级缓存) 订单(原料)(三级缓存)。
最后
根据跟进源码可以很清晰了解下,spring的循环依赖是通过启动初始化的时候在refresh那个方法对非懒加载的bean进行实例化,当然如果这里存在循环依赖注入的属性则进行属性初始化,通过二级就可以解决依赖的问题,三级缓存(singletonFactories)是用来解决像类似AOP代理这类的提前存放索引位置。代码比较繁琐建议debug跟进深入。
参考:
https://www.bilibili.com/video/BV18a411P7cq/
https://blog.csdn.net/weixin_43716742/article/details/124448697
https://www.zhihu.com/question/445446018
https://zhuanlan.zhihu.com/p/496273636
https://www.cnblogs.com/daimzh/p/13256413.html