循环依赖 循环依赖其实就是循环引用,即两个或者两个以上的bean互相持有对方,最终形成闭环
两大场景
第一种:构造器注入循环依赖
1 2 3 4 5 6 7 8 9 @Service public class AService { public AService (BService bService) { } } @Service public class BService { public BService (AService aService) { } }
结果:
1 2 3 4 5 6 7 The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | AService defined in file [D :\Java \springboot \springboot \target \classes \top \parak \depend \AService.class ] ↑ ↓ | BService defined in file [D :\Java \springboot \springboot \target \classes \top \parak \depend \BService.class ] └─────┘
Spring解决循环依赖依靠的是Bean的中间态,而这个中间态是指已经实例化,但未初始化。构造器执行是在中间态之前,因此构造器的循环依赖无法解决。
第二种:单例的setter注入
1 2 3 4 5 6 7 8 9 10 11 @Service public class AService { @Autowired private BService bService; } @Service public class BService { @Autowired private AService aService; }
这种场景经常使用,没有问题。
第三种:多例的setter注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Service public class AService { @Autowired private BService bService; } @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Service public class BService { @Autowired private AService aService; } @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) @Component public class CService { @Autowired private AService aService; }
结果:
1 2 3 4 5 6 7 8 The dependencies of some of the beans in the application context form a cycle: c (field private top.parak.depend.AService top.parak.depend.C.aService) ┌─────┐ | AService (field private top.parak.depend.BService top.parak.depend.AService.bService) ↑ ↓ | BService (field private top.parak.depend.AService top.parak.depend.BService.aService) └─────┘
没有使用缓存,每次都会生成一个新对象。
总结
构造器注入和prototype类型的field注入发生循环依赖时都无法初始化
field注入单例的bean时,尽管有循环依赖,但是bean可以成功初始化
如何检测 Bean在创建的时候可以给该Bean打个标志,如果递归调用回来发现正在创建中的话,即说明产生了循环依赖。
如何解决 DefaultSingletonBeanRegistry
内部属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { private final Map<String, Object> singletonObjects = new ConcurrentHashMap <>(256 ); private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap <>(16 ); private final Map<String, Object> earlySingletonObjects = new HashMap <>(16 ); private final Set<String> registeredSingletons = new LinkedHashSet <>(256 ); private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap <>(16 )); }
三级缓存:
缓存
级别
用途
singletonObjects
一级
存放最终单例,key为bean名称,value为bean实例。这里的bean实例指的是已经完全创建好的,即已经经历实例化->属性填充->初始化->后置处理过程的bean,可以直接使用。
earlySingletonObjects
二级
存放早期对象,key为bean名称,value为bean实例。这里的bean实例指的是仅完成实例化的bean,还未进行属性填充等后续操作。用于提前曝光,供别的bean引用,解决循环依赖。
singletonFactories
三级
存放回调方法,key为bean名称,value为bean工厂。在bean实例化之后,属性填充之前,如果允许提前曝光,Spring会把该bean转换为bean工厂并加入到三级缓存。在需要引用提前曝光对象时再通过工厂对象的getObject方法获取。
源码分析 IOC容器获取bean的入口为AbstractBeanFactory
的getBean
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { @Override public Object getBean (String name) throws BeansException { return doGetBean(name, null , null , false ); } protected <T> T doGetBean ( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object bean; Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null ) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } else { ... try { ... RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); ... if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } ... } } return (T) bean; } }
首先通过getSingleton(String beanName)
方法从三级缓存中获取bean实例,如果不为空则进行后续处理;如果为空,则通过getSingleton(String beanName, ObjectFactory<?) singletonFactory
方法创建bean实例并进行后续处理。
从三级缓存中获取bean实例的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { public Object getSingleton (String beanName) { return getSingleton(beanName, true ); } 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; } ... }
主要流程:
首先,尝试从一级缓存中singletonObjects
中获取单例Bean
获取不到,则从二级缓存earlySingletonObjects
中获取单例Bean
获取不到,则从三级缓存singletonFactories
中获取单例ObjectFactory
如果从三级缓存中获取成功,则将ObjectFactory
中的object
取出放入到二级缓存中,并将ObjectFactory
从三级缓存中移除
如果通过三级缓存的查找都没有找到目标bean实例,则通过getSingleton(String beanName, ObjectFactory<?> singleton)
方法创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public Object getSingleton (String beanName, ObjectFactory<?> singletonFactory) { ... synchronized (this .singletonObjects) { Object singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { ... beforeSingletonCreation(beanName); boolean newSingleton = false ; boolean recordSuppressedExceptions = (this .suppressedExceptions == null ); ... try { singletonObject = singletonFactory.getObject(); newSingleton = true ; } catch (IllegalStateException ex) { ... } finally { afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } } 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); } }
重点关注singletonFactory.getObject()
,singletonFactory
是一个函数式接口,对应AbstractBeanFactory
的doGetBean
方法中的lambda表达式:
1 2 3 4 5 6 7 8 9 10 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } });
重点关注createBean
方法,该方法为抽象方法,由AbstractBeanFactory
子类AbstractAutowireCapableBeanFactory
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 protected Object createBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'" ); } return beanInstance; } } protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null ; ... Object bean = instanceWrapper.getWrappedInstance(); ... synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } ... mbd.postProcessed = true ; } } boolean earlySingletonExposure = (mbd.isSingleton() && this .allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } ... if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false ); if (earlySingletonReference != null ) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } ... } } try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } ... return exposedObject; }
其中addSingletonFactory
方法在父类DefaultSingletonBeanRegistry
已实现:
1 2 3 4 5 6 7 8 9 10 11 protected void addSingletonFactory (String beanName, ObjectFactory<?> singletonFactory) { synchronized (this .singletonObjects) { if (!this .singletonObjects.containsKey(beanName)) { this .singletonFactories.put(beanName, singletonFactory); this .earlySingletonObjects.remove(beanName); this .registeredSingletons.add(beanName); } } }
整个流程总结如下:
面试逼问 (1)只用一级缓存是否可以解决循环依赖?
可以解决。
对于一级缓存,我们不等对象初始化完成之后再存入缓存,而是等对象实例化完成后就提前暴露,存入一级缓存,由于此时缓存对象并没有进行初始化操作,即早期对象。那么A实例化完成提前暴露早期对象,A在属性注入时,发现B不在容器中,也没有提前暴露,那么去进行B的生命周期,B实例化后进行属性注入,发现A提前暴露,那么B可以从一级缓存中获取到A的早期对象完成初始化,回到A的生命周期从而A也可以完成初始化。 但是这样会引发另一个问题:早期对象和完整对象都存在一级缓存中,如果此时来了其他线程并发获取bean,就可能从一级缓存中获取到bean的早期对象,这样明显不行,那么我们不得已在从一级缓存获取对象处加一个互斥锁,以避免这个问题。 加互斥锁代理来另一个问题:容器刷新完成后的普通获取bean的请求都需要竞争锁,如果这样处理,在高并发场景下使用Spring的性能必然降低。
(2)加上二级缓存有什么好处?
优化一级循环加锁带来的性能问题。
将对象的早期对象存入二级缓存中,一级缓存用于存储完整对象。 这样B在创建过程中进行属性注入时,先从一级缓存中获取A,获取失败则从二级缓存中获取。 这种获取bean的逻辑也可能出现其他线程获取到早期对象的问题,所以还是要加互斥锁。只不过这里的加锁逻辑可以下沉到二级缓存。那么普通的getBean请求可以直接从一级缓存获取对象,而不用去竞争锁。
(3)二级缓存如何解决AOP问题?
代理对象提前创建。
Spring支持以CGLIB和JDK动态代理的方式为对象创建代理类以提供AOP支持,代理对象的创建通常是在bean初始化完成之后进行(通过BeanPostProcessor后置处理器)。 如果没有循环依赖,那么代理对象依然在初始化完成后创建,如果有循环依赖,那么提前创建代理对象。 如何判断发生了循环依赖? 在B创建的过程中获取A的时候,发现二级缓存中有A,就说明发生了循环依赖,此时就为A创建代理对象,将其覆盖到二级缓存中,并且将代理对象复制给B的对应属性。 当出现多级循环依赖的时候,可以在对象实例化完成之后,将beanName存在一个Set中,标识对应的bean正在创建中,而当其他对象创建的过程依赖某个对象的时候,判断其是否在这个Set中,如果在就说明发生了循环依赖。
(4)那么三级缓存有什么作用?
虽然仅仅依靠二级缓存能够解决循环依赖和AOP的问题,但是从解决方案上来看,维护代理对象的逻辑和getBean的逻辑过于耦合。
三级缓存的key还是为beanName,但是value是一个函数(ObjectFactory#getBean方法),在该函数中执行获取早期对象的逻辑:getEarlyBeanReference方法。 在getEarlyBeanReference方法中,Spring会调用所有SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法,通过该方法可以修改早期对象的属性或者替换早期对象。这个是Spring留给开发者的另一个扩展点,虽然我们很少使用,不过在循环依赖遇到AOP的时候,代理对象就是通过这个后置处理器创建。
参考资料 [1] 🕊️ 鸟叔博客 [2] 💤 黑哥知乎