前言
了解Spring循环依赖和三级缓存需要熟悉IOC、AOP流程。
工作中常用new语句创建对象,通过new方法创建的对象是没有属性填充的,而Spring创建对象时可指定对象的生命周期;
说Spring的bean默认是单例的是因为Spring启动时只会生成单例对象放入单例池,即singletonBeanRegistry,而使用@Scope("prototype")注解标注的类是不会加载进单例池中的。
不理解spring注入方式的同学可以先看往期这篇:[Spring Dependency Injection]
观看本篇需要熟悉getBean流程:[ 简单理解Spring getBean流程]
介绍
循环依赖就是循环引用,指两个或则两个以上的bean互相依赖对方,最终形成闭环。比如“A对象依赖B对象,而B对象也依赖A对象”。
SpringIOC中分为两种情况:
Spring解决循环依赖的前提:
熟悉依赖注入方式的应该清楚,构造器注入是通过构造方法来生成对象,其必须要先获取属性,才能生成调用构造方法进行实例化,这种情况的循环依赖是无法解决的。
属性注入和setter注入时是需要使用autowried的,而构造器注入是不需要的。
熟悉autowried底层应该清楚,autowired是在实例化后、初始化完成前调用后置处理器从IOC容器中拿到bean通过反射来为对象属性赋值的。
网上找了一张图来说明A、B对象依赖注入方式不同时spring能否解决循环依赖。
非aop循环依赖
通过调用栈可以看出解决循环依赖的关键是在A对象填充属性前将一个匿名内部类ObjectFactory对象放在SingletonFactory(三级缓存)中,在有依赖对象A的对象B填充属性A时通过getSingleton方法的ObjectFactory.getObject() 直接调用内部类中专门用来获取A半成品对象的getEarlyBeanReference方法,从而完成填充属性。
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;
}
getEarlyBeanReference方法则会循环调用bean后置处理器的getEarlyBeanReference方法,非aop情况下,会调用两个后置处理器,其都是直接返回传参的bean,未做处理。
aop循环依赖
此处不讲解AOP如何生成代理对象,在下篇文章会进行讲解
在aop代理的情况下,则getEarlyBeanReference方法中会多出一个后置处理器;
在调用bean后置处理器的getEarlyBeanReference方法中,会通过wrapIfNecessary生成代理对象。
// Aop提前引用入口public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
熟悉AOP的应该清楚,aop代理对象是在初始化那一步的后置处理器的postProcessAfterInitialization方法中生成代理对象的,同样是wrapIfNecessary方法,和上面的getEarlyBeanReference方法都出自AbstractAutoProxyCreator类。
//AOP 创建代理对象入口public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//如果没有被提前代理过
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//最终会调用createProxy,创建代理bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}