循环依赖说明
- 最简单的循环依赖:A依赖B,B依赖A,两者会相互依赖
- 稍微复杂一点的循环依赖:A依赖B、C,B依赖A、C,C依赖A、B,三者之间相互依赖
Spring解决的循环依赖的前置条件
- Spring初始化时,可以正确处理循环依赖的问题,但是只是要求bean是单例的,而且是通过属性值注入的方式。以下两种情况出现循环依赖,Spring也解决不了:
- 出现循环依赖的bean不是单例的
- 循环依赖的属性值是通过构造函数注入的(该属性值存在于该类的构造函数中)
Spring一些基础性知识说明(解决循环依赖的基础)
- Spring有三种实例化对象的方式:
- 特殊的构造方法
- 无参的默认构造方法
- 工厂方法(factory-method)
- Spring在进行填充属性的操作之前,已经完成了对象的实例化(尽管这个bean所有的属性都为空)
- Spring填充属性的操作具体是由InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues方法完成的,具体的类:
- @Resource注解是由CommonAnnotationBeanPostProcessor类解析注入的
- @Autowired、@Value、@inject注解是由AutowiredAnnotationBeanPostProcessor类解析注入的
- Spring容器 DefaultSingletonBeanRegistry类一些属性的说明:
- earlySingletonObjects: Map<String, Object> 存放原始的bean对象用于解决循环依赖,注意:存到里面的对象还没有被填充属性
- singletonFactories:Map<String, ObjectFactory<?>> 存放 bean工厂对象解决循环依赖
- singletonObjects:Map<String, Object> 用于存放完全初始化好的 bean从该缓存中取出的 bean可以直接使用
- singletonsCurrentlyInCreation:Set 正在创建的bean名称
- registeredSingletons:Set 已经创建的单例bean的名称
Spring解决循环依赖的流程概述
-
在bean进行创建前,会给bean打上正在创建的标签(singletonsCurrentlyInCreation对象中加入这个beanName)
DefaultSingletonBeanRegistry# public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){ ... } protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } -
在bean实例化以后会将这个bean提前进行暴露(会将bean放入singletonFactories和registeredSingletons属性中)
AbstractAutowireCapableBeanFactory# protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } } DefaultSingletonBeanRegistry# protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } -
在进行属性注入时populateBean(beanName, mbd, instanceWrapper)时,会判断属性的类型,进行类型转换时,会从容器中获取对应的bean,如果没有,就会进入创建流程
//以 AutowiredAnnotationBeanPostProcessor为例说明属性注入 1. AutowiredAnnotationBeanPostProcessor# public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException; 2. InjectionMetadata# public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable; 3. AutowiredAnnotationBeanPostProcessor# protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable; 4.DefaultListableBeanFactory# public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException; 5.DefaultListableBeanFactory# public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { 6. DependencyDescriptor# public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException { return beanFactory.getBean(beanName); } 7. ... -
如果一个bean正在创建,这个bean是可以被获取的,会从singletonFactory中进行获取。
1. AbstractBeanFactory# protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException; 2. DefaultSingletonBeanRegistry# protected Object getSingleton(String beanName, boolean allowEarlyReference) { //从map中获取bean如果不为空直接返回,不再进行初始化工作 //讲道理一个程序员提供的对象这里一般都是为空的 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; }
附加说明
-
SmartInstantiationAwareBeanPostProcessor接口中getEarlyBeanReference方法中可以对提前暴露的bean进行处理
- 比如说处理aop的类AnnotationAwareAspectJAutoProxyCreator就会在getEarlyBeanReference对提前进行代理(如果需要的话)
-
Spring解决循环依赖引入了singletonFactories和earlySingletonObjects两个属性,其实如果只是处理前面说的最简单的那种循环依赖(两个对象之间),其实只需要singletonFactories属性就能够完成对应的操作。只有解决多个对象之间的循环依赖才会用到earlySingletonObjectss属性,主要是由于Spring对于提前暴露的bean也提供了接口进行前置化处理(上一条提到的AOP),为了避免这些处理重复进行所以才会用到earlySingletonObjects属性进行缓存处理好的前置对象,而不仅仅是获取对象的singletonFactories方法。
# DefaultSingletonBeanRegistry @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { //从map中获取bean如果不为空直接返回,不再进行初始化工作 //讲道理一个程序员提供的对象这里一般都是为空的 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; }