概述
循环依赖就是依赖关系形成环,比如最简单的循环依赖:A对象依赖B,B对象依赖A
属性注入与循环依赖
- 如果是构造器注入,如果循环依赖对象没法构建,因为还未实例化
- 如果是属性注入但是作用域是prototype,spring不会缓存其对象实例,也不能处理循环依赖的情况
- 如果是属性注入singleton的,其bean的实例化过程与属性注入过程是分开的,并且spring提供了三个map(就是大家说三级缓存)来实现。
spring属性注入处理循环依赖的方式
通过以下xml方式配置一个循环依赖的示例:
1
2
3
4
5
6
7
8
9
|
< bean id = "person1" class = "com.example.leetcode.spring.bean.Person" > < property name = "parent" ref = "person2" ></ property > < property name = "name" value = "tom" ></ property > </ bean > < bean id = "person2" class = "com.example.leetcode.spring.bean.Person" > < property name = "parent" ref = "person1" ></ property > < property name = "name" value = "jack" ></ property > </ bean > |
spring循环依赖处理几个关键位置:
获取bean对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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; // 这里会检查单例bean是否已经在注册表,并返回。 // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null ) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace( "Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference" ); } else { logger.trace( "Returning cached instance of singleton bean '" + beanName + "'" ); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } ... } |
DefaultSingletonBeanRegistry(单例对象注册表)的几个关键属性。
1
2
3
4
5
6
7
8
9
10
11
|
// 用来存储已经创建好的单例对象 /** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>( 256 ); // 用来存储单例beanname到ObjectFactory的映射 /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>( 16 ); // 用来提前存储还未初始化好的单例对象 /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>( 16 ); |
DefaultSingletonBeanRegistry.getSingleton()的实现.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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; } |
AbstractAutowireCapableBeanFactory.doCreateBean创建对象与注入属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
protected Object doCreateBean( final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { ... instanceWrapper = createBeanInstance(beanName, mbd, args); ... // 检查是否提前将单例bean存入缓存 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" ); } // 这里将beanname与工厂映射放入缓存注册表中(也就是上面的singletonFactories) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } ... // 注入依赖属性 populateBean(beanName, mbd, instanceWrapper); ... } |
假设我们从beanfactory获取person1对象, 循环依赖处理流程如下:
1.通过AbstractBeanFactory.doGetBean("persion1")获取对象
2.因为一开始通过DefaultSingletonBeanRegistry.getSingleton()什么都没有,进入AbstractAutowireCapableBeanFactory.doCreateBean()进行创建
3.AutowireCapableBeanFactory.doCreateBean()里面执行完创建逻辑,因为是singleton将beanname与工厂的映射加入到addSingletonFactory()到缓存
4.开始处理person1对象的属性依赖populateBean()
5.当发现person1的parent属性是一个引用时,通过beanfactory.getBean("person2")获取依赖对象(org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference)
6.此时进入person2的创建流程, person2也没有缓存,开始实例化并加入到addSingletonFactory()到缓存
7.person2在通过populateBean()注入属性依赖发现依赖person1, 此时通过beanfactory.getBean("person1")获取依赖对象
8.此时AbstractBeanFactory.doGetBean("persion1")获取对象执行到getSingleton("person1")进行以下判断:
- 从singletonObjects.get(beanName)获取到null
- 进入if条件,对singletonObjects同步
- 从earlySingletonObjects.get(beanName);获取也为null
- 进入内层if,通过singletonFactories.get(beanName);获取到最开始bean实例化之后的beanname与工厂缓存信息
- 获取到仅实例化完成的bean,并earlySingletonObjects.put(beanName, singletonObject);
- 然后删除singletonFactories.remove(beanName);
9.此时从getSingleton("person1")返回了一个仅实例化尚未注入的bean引用
10.person2在第7步获取到person1仅实例化未注入的对象引用。
11.person2完成属性注入并返回。
12.person2被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)缓存,并删除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
13.person1在5步获取到person2的对象并完成属性注入
14.person1对象返回(因为一开始person2获取的是person1的引用,此时person1完成注入是能看到注入后的对象)
15.person1被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)缓存,并删除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
16.返回最终的person1对象
关于三个map(三级缓存)
在出现循环依赖时,三个map之间的流程如下:
先从singletonFactories获取工厂,并通过getObject获取对象并移除缓存,将对象缓存到earlySingletonObjects
通过earlySingletonObjects获取提前曝光的对象
对象创建并初始化完成之后,对象信息保留在singletonObjects并移除过earlySingletonObjects中的缓存
earlySingletonObjects二级缓存是鸡肋吗?
earlySingletonObjects缓存的目的是,通过三级缓存在获取对象会执行一些列的后置处理器,通过earlySingletonObjects来缓存提升性能。
以上就是spring解决循环依赖的详细内容,更多关于sping 循环依赖的资料请关注服务器之家其它相关文章!
原文链接:https://juejin.im/post/6877734926121664526?utm_source=tuicool&utm_medium=referral