Spring源码|为什么使用构造器注入可以检测依赖循环

5,027 阅读7分钟

先说结论,因为带构造器产生依赖循环使不会把 bean 放进 earlySingletonObjects,导致 singletonObjects 一直为空后报错,所以使用构造器注入可以检测依赖循环。以下是详细的分析过程。

预备

给以下几个重要的方法设置断点

以下的方法都在 DefaultSingletonBeanRegistry 类里

getSingleton(String beanName, boolean allowEarlyReference)

image-20220213101032359

addSingleton(String beanName, Object singletonObject)

image-20220213101154613

addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)

image-20220213101102135

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

image-20220213101336348

beforeSingletonCreation(String beanName)

image-20220213101415466

afterSingletonCreation(String beanName)

image-20220213101441967

给每个断点添加条件

beanName.equals("wife") || beanName.equals("husband") || beanName.equals("singleDog") || beanName.equals("blindman")

image-20220211155530470

需要关注的变量

image-20220213101834408

image-20220213101853199

image-20220213101907458

image-20220213101921410

image-20220213102020706

依赖注入正常流程

@Autowired 注入

前提

谁被依赖

@Component
public class SingleDog {
}

谁需要依赖其他 bean

@Component
public class Blindman {

    @Autowired
    SingleDog singleDog;
}

过程

doGetBeanNamesForType() 内 allowEarlyReference 为 false

blindman 走 getSingleton(String beanName, boolean allowEarlyReference)

  • 判断

    • singletonObjects 无
      isSingletonCurrentlyInCreation false
      
  • 返回

    • null
      
  • singleDog 走 getSingleton(String beanName, boolean allowEarlyReference)

    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        

doGetBean() 内 allowEarlyReference 为 true

  • blindman 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    • blindman 走 getSingleton(String beanName, boolean allowEarlyReference)

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • blindman 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

      • 判断

        • singletonObjects 无
          
      • blindman 走 beforeSingletonCreation(String beanName)

        • singletonsCurrentlyInCreation:{"blindman"}
          
      • blindman 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

        • blindman 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • blindman 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • blindman 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
            • 结果

              • singletonFactories:{"blindman"}
                earlySingletonObjects:{}
                registeredSingletons:{"blindman",...}
                
            • blindman 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 进入遍历执行 InstantiationAwareBeanPostProcessor 对象的 postProcessProperties() 方法

              • singleDog 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
                • singleDog 走 getSingleton(String beanName, boolean allowEarlyReference)

                  • singletonObjects 无
                    isSingletonCurrentlyInCreation false
                    
                • singleDog 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

                  • 判断

                    • singletonObjects 无
                      
                  • singleDog 走 beforeSingletonCreation(String beanName)

                    • singletonsCurrentlyInCreation:{"blindman","singleDog"}
                      
                  • singleDog 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

                    • singleDog 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                      • singleDog 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                      • singleDog 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
                        • 结果

                          • singletonFactories:{"blindman","singleDog"}
                            earlySingletonObjects:{}
                            registeredSingletons:{"blindman","singleDog",...}
                            
                      • singleDog 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
                  • singleDog 走 afterSingletonCreation(String beanName)

                    • 结果

                      • singletonsCurrentlyInCreation:{"blindman"}
                        
                  • singleDog 走 addSingleton(String beanName, Object singletonObject)

                    • 结果

                      • singletonObjects:{"singleDog"}
                        singletonFactories:{"blindman"}
                        registeredSingletons:{"blindman","singleDog",...}
                        
      • blindman 走 afterSingletonCreation(String beanName)

        • 结果

          • singletonsCurrentlyInCreation:{}
            
      • blindman 走 addSingleton(String beanName, Object singletonObject)

        • 结果

          • singletonObjects:{"singleDog","blindman"}
            singletonFactories:{}
            registeredSingletons:{"blindman","singleDog",...}
            

测试数据

image-20220212121757997

构造器注入

前提

谁被依赖

@Component
public class SingleDog {
}

谁需要依赖其他 bean

@Component
public class Blindman {

    private final SingleDog singleDog;

    @Autowired
    public Blindman(SingleDog singleDog) {
        this.singleDog = singleDog;
    }
}

过程

doGetBeanNamesForType() 内 allowEarlyReference 为 false

  • singleDog 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        
  • blindman 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        

doGetBean() 内 allowEarlyReference 为 true

  • blindman 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    • blindman 走 getSingleton(String beanName, boolean allowEarlyReference)

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • blindman 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

      • 判断

        • singletonObjects 无
          
      • blindman 走 beforeSingletonCreation(String beanName)

        • singletonsCurrentlyInCreation:{"blindman"}
          
      • blindman 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

        • blindman 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • blindman 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            • singleDog 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
              • singleDog 走 getSingleton(String beanName, boolean allowEarlyReference)

                • singletonObjects 无
                  isSingletonCurrentlyInCreation false
                  
              • singleDog 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

                • 判断

                  • singletonObjects 无
                    
                • singleDog 走 beforeSingletonCreation(String beanName)

                  • singletonsCurrentlyInCreation:{"blindman","singleDog"}
                    
                • singleDog 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

                  • singleDog 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • singleDog 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • singleDog 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
                      • 结果

                        • singletonFactories:{"singleDog"}
                          earlySingletonObjects:{}
                          registeredSingletons:{"singleDog",...}
                          
                    • singleDog 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
                • singleDog 走 afterSingletonCreation(String beanName)

                  • 结果 *
                    singletonsCurrentlyInCreation:{"blindman"}
                    
                • singleDog 走 addSingleton(String beanName, Object singletonObject)

                  • 结果

                    • singletonObjects:{"singleDog"}
                      singletonFactories:{}
                      earlySingletonObjects:{}
                      registeredSingletons:{"singleDog",...}
                      
          • blindman 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
            • 结果

              • singletonFactories:{"blindman"}
                earlySingletonObjects:{}
                registeredSingletons:{"singleDog","blindman",...}
                
          • blindman 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
      • blindman 走 afterSingletonCreation(String beanName)

        • 结果

          • singletonsCurrentlyInCreation:{}
            
      • blindman 走 addSingleton(String beanName, Object singletonObject)

        • 结果

          • singletonObjects:{"singleDog","blindman"}
            singletonFactories:{}
            earlySingletonObjects:{}
            registeredSingletons:{"singleDog","blindman",...}
            

测试数据

image-20220212235542482

比较 @Autowired 注入和构造器注入

autowired vs 构造器 可以发现两者的区别体现在绿框框住的部分上。

<现象一>

@Autowired 注入会把识别到的 bean 都放到 singletonFactories 和 registeredSingletons 中;因为 blindman 依赖 singleDog,构造器注入会先把 blindman 依赖的 singleDog 放到 singletonFactories 和 registeredSingletons 中,等 singleDog 被放到 singletonObjects 时,blindman 才会被放到 singletonFactories 和 registeredSingletons 中,最终 blindman 也被放到了 singletonObjects。

复现依赖循环

不带构造器注入

前提

非构造器注入

@Component
public class Wife {

    @Autowired
    private Husband husband;
}

非构造器注入

@Component
public class Husband {

    @Autowired
    private Wife wife;
}

过程

doGetBeanNamesForType() 内 allowEarlyReference 为 false

  • husband 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        
  • wife 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        

doGetBean() 内 allowEarlyReference 为 true

  • husband 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    • husband 走 getSingleton(String beanName, boolean allowEarlyReference)

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • husband 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

      • 判断

        • singletonObjects 无
          
      • husband 走 beforeSingletonCreation(String beanName)

        • singletonsCurrentlyInCreation:{"husband"}
          
      • husband 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

        • husband 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • husband 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • husband 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
            • 结果

              • singletonFactories:{"husband"}
                earlySingletonObjects:{}
                registeredSingletons:{"husband"}
                
          • husband 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 进入遍历执行 InstantiationAwareBeanPostProcessor 对象的 postProcessProperties() 方法
            • wife 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
              • wife 走 getSingleton(String beanName, boolean allowEarlyReference)

                • singletonObjects 无
                  isSingletonCurrentlyInCreation false
                  
              • wife 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

                • 判断

                  • singletonObjects 无
                    
                • wife 走 beforeSingletonCreation(String beanName)

                  • singletonsCurrentlyInCreation:{"wife","husband"}
                    
                • wife 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

                  • wife 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • wife 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • wife 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
                      • 结果

                        • singletonFactories:{"husband","wife"}
                          earlySingletonObjects:{}
                          registeredSingletons:{"husband","wife"}
                          
                    • wife 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 进入遍历执行 InstantiationAwareBeanPostProcessor 对象的 postProcessProperties() 方法
                      • husband 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
                        • husband 走 getSingleton(String beanName, boolean allowEarlyReference)
                          • 判断

                            • singletonObjects 无
                              isSingletonCurrentlyInCreation true
                              earlySingletonObjects 无
                              allowEarlyReference true
                              singletonFactories 有
                              
                          • 结果

                            • earlySingletonObjects:{"husband"}
                              singletonFactories:{"wife"}
                              
                          • 返回

                            • 通过 singletonFactories 内获得的 bean
                              
                • wife 走 afterSingletonCreation(String beanName)

                  • 结果

                    • singletonsCurrentlyInCreation:{"husband"}
                      
                • wife 走 addSingleton(String beanName, Object singletonObject)

                  • 结果

                    • singletonObjects:{"wife",...}
                      singletonFactories:{}
                      earlySingletonObjects:{"husband"}
                      registeredSingletons:{"husband","wife",...}
                      
      • husband 走 afterSingletonCreation(String beanName)

        • 结果

          • singletonsCurrentlyInCreation:{}
            
      • husband 走 addSingleton(String beanName, Object singletonObject)

        • 结果

          • singletonObjects:{"wife","husband",...}
            singletonFactories:{}
            earlySingletonObjects:{}
            registeredSingletons:{"husband","wife",...}
            

测试数据

image-20220212112516103

带构造器注入

前提

非构造器注入

@Component
public class Wife {

    @Autowired
    private Husband husband;
}

构造器注入

@Component
public class Husband {

    private final Wife wife;
    
    @Autowired
    public Husband(Wife wife) {
        this.wife = wife;
    }
}

过程

doGetBeanNamesForType() 内 allowEarlyReference 为 false

  • husband 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        
  • wife 走 getSingleton(String beanName, boolean allowEarlyReference)
    • 判断

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • 返回

      • null
        

doGetBean() 内 allowEarlyReference 为 true

  • husband 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    • husband 走 getSingleton(String beanName, boolean allowEarlyReference)

      • singletonObjects 无
        isSingletonCurrentlyInCreation false
        
    • husband 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

      • 判断

        • singletonObjects 无
          
      • husband 走 beforeSingletonCreation(String beanName)

        • singletonsCurrentlyInCreation:{"husband"}
          
      • husband 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

        • husband 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          • husband 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            • wife 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
              • wife 走 getSingleton(String beanName, boolean allowEarlyReference)

                • singletonObjects 无
                  isSingletonCurrentlyInCreation false
                  
              • wife 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

                • 判断

                  • singletonObjects 无
                    
                • wife 走 beforeSingletonCreation(String beanName)

                  • singletonsCurrentlyInCreation:{"wife","husband"}
                    
                • wife 走 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

                  • wife 走 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • wife 走 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                    • wife 走 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
                      • 结果

                        • singletonFactories:{"wife"}
                          earlySingletonObjects:{}
                          registeredSingletons:{"wife"}
                          
                    • wife 走 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
                      • husband 走 doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
                        • husband 走 getSingleton(String beanName, boolean allowEarlyReference)
                          • 判断

                            • singletonObjects 无
                              isSingletonCurrentlyInCreation true
                              earlySingletonObjects 无
                              allowEarlyReference true
                              singletonFactories 无
                              
                            • 返回

                              • null
                                
                        • husband 走 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
                          • 判断

                            • singletonObjects 无
                              // 当前从创建检查中排除的 bean 的名称
                              inCreationCheckExclusions 无
                              // 当前正在创建的 bean 的名称
                              singletonsCurrentlyInCreation 有
                              
                            • husband 走 beforeSingletonCreation(String beanName) image-20220210180644826
                              • beforeSingletonCreation() 抛出异常

测试结果

image-20220212114721701

比较不带构造器的依赖循环和 @Autowired 注入的正常流程

不带构造器 vs @Autowired 注入.jpg

绿框内的部分为两者的区别。两者一开始都会把 bean 放到 singletonFactories 和 registeredSingletons 中,==当 不带构造器的依赖循环 检测到依赖循环时,husband 被放到了 earlySingletonObjects 中,然后等待 wife 处理完并被放到 singletonObjects 后才继续处理 husband==。

比较带构造器的依赖循环和带构造器的正常流程

带构造器的正常 vs 带构造器依赖循环.jpg

两者在绿框之前的现象和 <现象一> 一致。到绿框部分时,带构造器的依赖循环 会把被依赖对象 singleDog 放进 singletonObjects 中,而 带构造器的正常流程 检测到依赖循环会卡死。

比较不带构造器和带构造器的依赖循环

不带构造器 vs 带构造器.jpg

在第一个绿框处的现象和 <现象一> 的绿框处一致。在第二个绿框处,不带构造器 会将 husband 从 singletonFactories 移动到 earlySingletonObjects 中,而 带构造器 则没有执行同样的步骤。

总结

带构造器的依赖循环之所以会报错是因为其不会把 bean 放进 earlySingletonObjects,导致 singletonObjects 一直为空

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!