• Spring IOC - Bean的生命周期之依赖注入


            在Spring启动流程中,创建的factoryBean是DefaultListableBeanFactory,其类图如下所示:

            可以看到其直接父类是AbstractAutoireCapableBeanFactory,他主要负责完成Bean的自动装配和创建工作。 具体来说,AbstractAutowireCapableBeanFactory会完成以下工作:

    1. 根据Bean的定义信息创建Bean实例;
    2. 根据Bean的定义信息完成Bean的依赖注入;
    3. 根据Bean的定义信息完成Bean的初始化工作;
    4. 返回创建好的Bean实例。

            其中,属性注入是AbstractAutowireCapableBeanFactory的核心功能之一。它会根据Bean的定义信息,自动将依赖的Bean注入到当前Bean中。具体来说,它会根据Bean的依赖关系,自动查找并创建依赖的Bean实例,并将其注入到当前Bean中。

             除了属性注入,AbstractAutowireCapableBeanFactory还支持构造函数注入、工厂方法注入等多种注入方式,可以满足不同场景下的需求。

            其核心方法AbstractAutowireCapableBeanFactory#populateBean,下面,我们看一下populateBean方法是怎么进行依赖注入的。它处理Spring的各种依赖注入:包括自动注入(名称注入和类型注入)、注解注入(@Autowired和@Value等)、手动注入等。

    1. 首先,判断是否需要进行属性注入。调用 ibp#postProcessAfterInstantiation

    2. 自动注入:包括名称注入和类型注入。不推荐使用,只支持 XML 配置方式。

    3. 注解注入:处理 @Autowired 和 @Value 等注解,Spring 提供 ibp#postProcessProperties 可以调整 bean 实例。如 AutowiredAnnotationBeanPostProcessor 用于处理 @Autowired 和 @Value 注解。CommonAnnotationBeanPostProcessor 用于处理 @Resource 注解。

    4. 依赖检查:检查要注入的依赖是否已经完整。可以只检查简单类型(Java 原生类型、Enum、Class 等),也可以只检查对象类型。

    5. 手动注入:最基础的注入方式,实际上都委托给了 BeanWrapper 处理。

    1. protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    2. // 1. 判断是否需要进行属性注入:ibp#postProcessAfterInstantiation
    3. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    4. for (BeanPostProcessor bp : getBeanPostProcessors()) {
    5. if (bp instanceof InstantiationAwareBeanPostProcessor) {
    6. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    7. if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    8. return;
    9. }
    10. }
    11. }
    12. }
    13. PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    14. // 2. 自动注入:包括名称注入和类型注入
    15. int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    16. if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    17. MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    18. // 2.1 自动根据名称注入
    19. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
    20. autowireByName(beanName, mbd, bw, newPvs);
    21. }
    22. // 2.2 自动根据类型注入
    23. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    24. autowireByType(beanName, mbd, bw, newPvs);
    25. }
    26. pvs = newPvs;
    27. }
    28. boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    29. boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    30. // 3. 注解注入:后置处理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在这处理的。
    31. PropertyDescriptor[] filteredPds = null;
    32. if (hasInstAwareBpps) {
    33. if (pvs == null) {
    34. pvs = mbd.getPropertyValues();
    35. }
    36. for (BeanPostProcessor bp : getBeanPostProcessors()) {
    37. if (bp instanceof InstantiationAwareBeanPostProcessor) {
    38. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    39. PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    40. if (pvsToUse == null) {
    41. if (filteredPds == null) {
    42. filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    43. }
    44. pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    45. if (pvsToUse == null) {
    46. return;
    47. }
    48. }
    49. pvs = pvsToUse;
    50. }
    51. }
    52. }
    53. // 4. 依赖检查,循环依赖...
    54. if (needsDepCheck) {
    55. if (filteredPds == null) {
    56. filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    57. }
    58. checkDependencies(beanName, mbd, filteredPds, pvs);
    59. }
    60. // 5. 手动依赖注入
    61. if (pvs != null) {
    62. applyPropertyValues(beanName, mbd, bw, pvs);
    63. }
    64. }

            这里重点讲解AutowiredAnnotationBeanPostProcessor为代表的注解注入方式。其会调用到Spring进行依赖查找的核心API: beanFactory#resolveDependency,其本质是根据类型查找依赖,调用beanFactory#beanNamesForType方法根据类型查找依赖名称。他解决了以下四个场景:

    1. Optional:JDK8 提供了 API。主要是将依赖设置非强制依赖,即 descriptor.required=false。

    2. 延迟依赖注入支持:ObjectFactory、ObjectProvider、javax.inject.Provider

    3. 另一种延迟注入的支持 - @Lazy 属性。

    4. 根据类型查找依赖 - doResolveDependency。

    1. @Override
    2. public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    3. // ParameterNameDiscovery用于解析方法参数名称
    4. descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    5. // 1. Optional
    6. if (Optional.class == descriptor.getDependencyType()) {
    7. return createOptionalDependency(descriptor, requestingBeanName);
    8. // 2. ObjectFactory、ObjectProvider
    9. } else if (ObjectFactory.class == descriptor.getDependencyType() ||
    10. ObjectProvider.class == descriptor.getDependencyType()) {
    11. return new DependencyObjectProvider(descriptor, requestingBeanName);
    12. // 3. javax.inject.Provider
    13. } else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
    14. return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    15. } else {
    16. // 4. @Lazy
    17. Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
    18. descriptor, requestingBeanName);
    19. // 5. 正常情况
    20. if (result == null) {
    21. result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    22. }
    23. return result;
    24. }
    25. }

            最底层都会调用beanFactory#doResolveDependency方法,其封装了依赖查找的各种情况。

    1. 快速查找: @Autowired 注解处理场景。AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注解时,如果注入的对象只有一个,会将该 bean 对应的名称缓存起来,下次直接通过名称查找会快很多。

    2. 注入指定值:@Value 注解处理场景。QualifierAnnotationAutowireCandidateResolver 处理 @Value 注解时,会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换,这也是一般的处理过程,BeanDefinitionValueResolver 处理 String 对象也是这个过程。

    3. 集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。

    4. 单个依赖查询:先调用 findAutowireCandidates 查找所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority -> ③方法名称或字段名称。

    1. public Object doResolveDependency(DependencyDescriptor descriptor, String beanName, Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    2. InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    3. try {
    4. // 1. 快速查找,根据名称查找。AutowiredAnnotationBeanPostProcessor用到
    5. Object shortcut = descriptor.resolveShortcut(this);
    6. if (shortcut != null) {
    7. return shortcut;
    8. }
    9. // 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value会用到
    10. Class type = descriptor.getDependencyType();
    11. Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    12. if (value != null) {
    13. if (value instanceof String) {
    14. // 2.1 占位符解析
    15. String strVal = resolveEmbeddedValue((String) value);
    16. BeanDefinition bd = (beanName != null && containsBean(beanName) ?
    17. getMergedBeanDefinition(beanName) : null);
    18. // 2.2 Spring EL 表达式
    19. value = evaluateBeanDefinitionString(strVal, bd);
    20. }
    21. TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    22. try {
    23. // 2.3 类型转换
    24. return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
    25. } catch (UnsupportedOperationException ex) {
    26. return (descriptor.getField() != null ?
    27. converter.convertIfNecessary(value, type, descriptor.getField()) :
    28. converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
    29. }
    30. }
    31. // 3. 集合依赖,如 Array、List、Set、Map。内部查找依赖也是使用findAutowireCandidates
    32. Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    33. if (multipleBeans != null) {
    34. return multipleBeans;
    35. }
    36. // 4. 单个依赖查询
    37. Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    38. // 4.1 没有查找到依赖,判断descriptor.require
    39. if (matchingBeans.isEmpty()) {
    40. if (isRequired(descriptor)) {
    41. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    42. }
    43. return null;
    44. }
    45. String autowiredBeanName;
    46. Object instanceCandidate;
    47. // 4.2 有多个,如何过滤
    48. if (matchingBeans.size() > 1) {
    49. // 4.2.1 @Primary -> @Priority -> 方法名称或字段名称匹配
    50. autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
    51. // 4.2.2 根据是否必须,抛出异常。注意这里如果是集合处理,则返回null
    52. if (autowiredBeanName == null) {
    53. if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
    54. return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
    55. } else {
    56. return null;
    57. }
    58. }
    59. instanceCandidate = matchingBeans.get(autowiredBeanName);
    60. } else {
    61. // We have exactly one match.
    62. Map.Entry entry = matchingBeans.entrySet().iterator().next();
    63. autowiredBeanName = entry.getKey();
    64. instanceCandidate = entry.getValue();
    65. }
    66. // 4.3 到了这,说明有且仅有命中一个
    67. if (autowiredBeanNames != null) {
    68. autowiredBeanNames.add(autowiredBeanName);
    69. }
    70. // 4.4 实际上调用 getBean(autowiredBeanName, type)。但什么情况下会出现这种场景?
    71. if (instanceCandidate instanceof Class) {
    72. instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    73. }
    74. Object result = instanceCandidate;
    75. if (result instanceof NullBean) {
    76. if (isRequired(descriptor)) {
    77. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    78. }
    79. result = null;
    80. }
    81. if (!ClassUtils.isAssignableValue(type, result)) {
    82. throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
    83. }
    84. return result;
    85. } finally {
    86. ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    87. }
    88. }

            这里重点看下看下第四种单个依赖的查询,集合依赖与其异曲同工:

    1. 查找容器中所有可用依赖:findAutowireCandidates 方法根据类型查找依赖。

    2. 如何有多个依赖怎么处理?其实 Spring 有一套通用的流程,先按 @Primary 查找,再按 @Priority,最后按方法名称或字段名称查找,直到只有一个 bean 为止。相关的匹配规则见 determineAutowireCandidate 方法。

    3. 此时只有一个依赖,从容器获取真实的 bean。descriptor.resolveCandidate 方法根据名称 autowiredBeanName 实例化对象。

            从 findAutowireCandidates 方法,我们可以看到 Spring IoC 依赖注入的来源:

    1. 先查找 Spring IoC 内部依赖 resolvableDependencies。在 AbstractApplicationContext#prepareBeanFactory 方法中默认设置了如下内部依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

    2. 在父子容器进行类型查找:查找类型匹配的 beanNames,beanFactory#beanNamesForType 方法根据类型查找是,先匹配单例实例类型(包括 Spring 托管 Bean),再匹配 BeanDefinition 的类型。从这一步,我们可以看到 Spring 依赖注入的另外两个来源:一是 Spring 托管的外部 Bean,二是 Spring BeanDefinition。

    1. protected Map findAutowireCandidates(
    2. @Nullable String beanName, Class requiredType, DependencyDescriptor descriptor) {
    3. Map result = new LinkedHashMap<>(candidateNames.length);
    4. // 1. Spring IoC 内部依赖 resolvableDependencies
    5. for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
    6. Class autowiringType = classObjectEntry.getKey();
    7. if (autowiringType.isAssignableFrom(requiredType)) {
    8. Object autowiringValue = classObjectEntry.getValue();
    9. autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
    10. if (requiredType.isInstance(autowiringValue)) {
    11. result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
    12. break;
    13. }
    14. }
    15. }
    16. // 2. 类型查找:本质上递归调用beanFactory#beanNamesForType。先匹配实例类型,再匹配bd。
    17. String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    18. this, requiredType, true, descriptor.isEager());
    19. for (String candidate : candidateNames) {
    20. // 2.1 isSelfReference说明beanName和candidate本质是同一个对象
    21. // isAutowireCandidate进一步匹配bd.autowireCandidate、泛型、@@Qualifier等进行过滤
    22. if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
    23. // 2.2 添加到候选对象中
    24. addCandidateEntry(result, candidate, descriptor, requiredType);
    25. }
    26. }
    27. // 3. 补偿机制:如果依赖查找无法匹配,怎么办?包含泛型补偿和自身引用补偿两种。
    28. if (result.isEmpty()) {
    29. boolean multiple = indicatesMultipleBeans(requiredType);
    30. // 3.1 fallbackDescriptor: 泛型补偿,实际上是允许注入对象类型的泛型存在无法解析的情况
    31. DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
    32. // 3.2 补偿1:不允许自称依赖,但如果是集合依赖,需要过滤非@Qualifier对象。什么场景?
    33. for (String candidate : candidateNames) {
    34. if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
    35. (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
    36. addCandidateEntry(result, candidate, descriptor, requiredType);
    37. }
    38. }
    39. // 3.3 补偿2:允许自称依赖,但如果是集合依赖,注入的集合依赖中需要过滤自己
    40. if (result.isEmpty() && !multiple) {
    41. for (String candidate : candidateNames) {
    42. if (isSelfReference(beanName, candidate) &&
    43. (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
    44. isAutowireCandidate(candidate, fallbackDescriptor)) {
    45. addCandidateEntry(result, candidate, descriptor, requiredType);
    46. }
    47. }
    48. }
    49. }
    50. return result;
    51. }

            findAutowireCandidates 大致可以分为三步:先查找内部依赖,再根据类型查找,最后没有可注入的依赖则进行补偿。

    1. 查找内部依赖:Spring IoC 容器本身相关依赖,这部分内容是用户而言是透明的,也不用感知。resolvableDependencies 集合中注册如 BeanFactory、ApplicationContext 、ResourceLoader、ApplicationEventPublisher 等。

    2. 根据类型查找:包括 ①外部托管 Bean ②注册 BeanDefinition。类型查找调用 beanFactory#beanNamesForType 方法。

      1. 自身引用:isSelfReference 方法判断 beanName 和 candidate 是否是同一个对象,包括两种情况:一是名称完全相同,二是 candidate 对应的工厂对象创建了 beanName。

      2. 是否可以注入:底层实际调用 resolver.isAutowireCandidate 方法进行过滤,包含三重规则:①bd.autowireCandidate=true -> ②泛型匹配 -> ③@Qualifier。下面会详细介绍这个方法。

    3. 补偿机制:如果依赖查找无法匹配,怎么办?Spring 提供了两种补偿机制:一是泛型补偿,允许注入对象对象的泛型无法解析,二是自身引用补偿,对这两种机制使用如下:

      1. 先使用泛型补偿,不允许自身引用:即 fallbackDescriptor。此时如果是集合依赖,对象必须是 @Qualifier 类型。

      2. 允许泛型补偿和自身引用补偿:但如果是集合依赖,必须过滤自己本身,即 beanName.equals(candidate) 必须剔除。

  • 相关阅读:
    【C++】红黑树的插入实现
    .NET Emit 入门教程:第六部分:IL 指令:5:详解 ILGenerator 指令方法:创建实例指令
    视频剪辑技巧:简单步骤,批量剪辑并随机分割视频
    [linux]信号处理:信号编码、基本API、自定义函数和集合操作的详解
    【Unity实战】实现强大通用易扩展的对话系统(附项目源码)
    云服务器ECS价格表出炉_2024年最新价格表——阿里云
    图像处理领域之►边缘检测大合集◄【应该是全网仅有的了吧】
    三年城市NOH落地100城,毫末智行内部信剑指2025
    免费领取源码-小程序+spring boot流浪动物救助系统 12783
    维修Balance Monitor动平衡仪触摸屏 SB-7705s工控电脑
  • 原文地址:https://blog.csdn.net/zhangweiocp/article/details/134492750