Loading

Spring解决循环依赖

什么是循环依赖?

在我们实际开发中,可能会碰到A业务的Service需要调用B业务Service中的某个方法,
并且B业务Service也要调用A.Service的某个方法,这样,就会形成循环依赖。

如下代码,就形成了AService和BService的循环依赖。

@Service
public class AService {	
	@Autowired
	private BService bService;
}

@Service
public class BService {
	@Autowired
	private AService aService;
}

Spring中循环依赖的场景

  • 构造器循环依赖。(未解决)
  • 依赖注入Field字段的循环依赖。(已解决)

Spring解决循环依赖的思路

Bean创建过程
Bean的创建从整体上讲分为三个阶段
createBeanInstance() 拿到BeanWrapper对象,在创建过程中将半成品的Bean放入三级缓存(稍后再说缓存)
populateBean() 属性赋值
initializeBean() 初始化Bean实例
三级缓存
Bean的创建都是通过getBean()方法来实现的。
在DefaultSingletonBeanRegistry类中,我们可以看到几个Map缓存
/** Cache of singleton objects: bean name to bean instance. */
/** 一级缓存,缓存单例Bean,key为beanName, value是Bean实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
/** 二级缓存,缓存单例Bean工厂,key为beanName,value为bean工厂 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
/** 三级缓存,字面意思,缓存早期的bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Names of beans that are currently in creation. */
/** 正在创建的bean,比如果构造器初始化时,A初始化参数为B,调用A的构造器,但是B还未创建,就会先去创建B,此时A就属于正在创建 */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
getSingleton()
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 先从一级缓存中获取单例对象
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果一级缓存中没有,并且当前的bean正在创建
    // isSingletonCurrentlyInCreation(beanName)就是判断singletonsCurrentlyInCreation中有没有beanName
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 如果当前bean正在创建,就从二级缓存中获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果二级缓存中还没有,并且允许从三级缓存中获取
            if (singletonObject == null && allowEarlyReference) {
                // 从三级缓存中获取Factory
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 如果三级缓存中有,就把三级缓存中的对象移动到二级缓存中去,并移除三级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

getSingleton()方法的调用发生在createBeanInstance()之后,也就是此时单例bean对象已经创建好了,虽然没进行依赖注入和实例化,但是可以提前抛出来当做标记使用。

doCreateBean()

doCreateBean()是Bean创建的核心,包含了createBeanInstance(),populateBean(),initializeBean(),

以下只保留核心代码,详细的可以到AbstractAutowireCapableBeanFactory中看doCreateBean()方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		// 创建BeanWrapper对象
		BeanWrapper instanceWrapper = null;
		if (instanceWrapper == null) {
             // 给BeanWrapper对象赋值
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
    	// 添加三级缓存
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		Object exposedObject = bean;
		try {
             // 对象属性赋值
			populateBean(beanName, mbd, instanceWrapper);
             // 实例化Bean
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

		if (earlySingletonExposure) {
            // 调用getSingleton();
		   Object earlySingletonReference = getSingleton(beanName, false);
        }
		return exposedObject;
	}
populateBean()

在依赖注入的过程中,会调用getBean()方法创建注入类的实例。只贴核心代码

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// 按name注入
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// 按type注入
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
	}
}

// 随便看一个,按名称注入的
protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
                 // 调用getBean()方法获取bean实例,如果没有,则会创建
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				registerDependentBean(propertyName, beanName);
			}
		}
	}

结语
从上面的一串代码逻辑中可以看出,循环依赖的主要处理逻辑在getSingleton()方法中,但是前提准备工作在createBeanInstance()中。
举例说明:
A依赖B,B也依赖A。
A进行第一步操作,完成了createBeanInstance(),并将自己放入了三级缓存
A进行第二部操作populateBean(A),在注入的过程中,调用getBean(B)创建B的实例。
B调用了getBean(B)后,在createBeanInstance(B)时,发现自己依赖了A,于是调用getBean(A)
此时再进入getsingleton(A)时,一级缓存是没有数据的,二级缓存也没有,但是三级缓存是有A的。
B相当于可以拿到了A对象(虽然不完整,但是可以完成初始化),就能完成整个初始化过程,也就是完整的实例化Bean
B完成初始化后,将自己放入一级缓存,此时回到A对象,A对象也能从一级缓存拿到B对象的实例,也就能完成自己的实例化。
由于B中的A是引用传递,所以此时B中的A引用也就完成了赋值。
A和B都完成了实例化,循环引用完美解决。
Spring通过此方式解决了依赖注入的循环依赖,但是如果是构造器的循环依赖,Spring是无法解决的。
因为三级缓存是在createBeanInstance()之后放入的,但是构造器的赋值是在createBeanInstance()里面执行的。
具体的可以看看createBeanInstance()的autowireConstructor()方法。
posted @ 2021-04-23 13:09  风吹屁屁疼  阅读(105)  评论(0编辑  收藏  举报