SpringloC容器的依赖注入源码解析(9)—— populateBean

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 站在设计者的角度设计populateBean:调用Bean的Setter方法实例去给Bean设置上属性值变量类型的转换,同时还要考虑处理集合类型的情况

站在设计者的角度设计populateBean:


调用Bean的Setter方法实例去给Bean设置上属性值


变量类型的转换,同时还要考虑处理集合类型的情况


配置的时候都是以字符串的形式来配置的

处理显式自动装配的逻辑(autowire = byName或byType)


22.png

用两个类来做测试,GirlFriend类中注入了BoyFriend的实例,BoyFriend中注入了自己的实例:


package com.wjw.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class BoyFriend {
   @Autowired
   private BoyFriend boyFriend;
}


package com.wjw.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class GirlFriend {
   @Autowired
   private BoyFriend boyFriend;
}

从AbstractAutowireCapableBeanFactory的doCreateBean方法中进入


protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
      if (mbd.hasPropertyValues()) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
        // Skip property population phase for null instance.
        return;
      }
    }
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }
    // 如果上面设置continueWithPropertyPopulation = false,表明用户可能已经自己填充了
    // bean的属性,不需要Spring帮忙填充了。此时直接返回即可
    if (!continueWithPropertyPopulation) {
      return;
    }
    // pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,
    // 提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
    // 获取BeanDefinition里面为Bean设置上的属性值
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
    }
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
      if (pvs == null) {
        pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          // 在这里会对@Autowired标记的属性进行依赖注入
          PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
          if (pvsToUse == null) {
            if (filteredPds == null) {
              filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
              return;
            }
          }
          pvs = pvsToUse;
        }
      }
    }
    // 依赖检查,对应depend-on属性,3.0已经弃用此属性
    if (needsDepCheck) {
      // 过滤出所有需要进行依赖检查的属性编辑器
      if (filteredPds == null) {
        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
    }
    if (pvs != null) {
      // 最终将属性注入到Bean的Wrapper实例里,这里的注入主要是供
      // 显式配置了autowiredbyName或者ByType的属性注入,
      // 针对注解来讲,由于在AutowiredAnnotationBeanPostProcessor已经完成了注入,
      // 所以此处不执行
      applyPropertyValues(beanName, mbd, bw, pvs);
    }
  }

最开始是一些判空逻辑:

23.png

接下来的逻辑就是脑图里的第一步了:


boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
         }
      }
   }
}

首先判断出boyfriend不是spring内部特殊的bean


!mbd.isSynthetic()

再看下容器里是否已经注册了InstantiationAwareBeanPostProcessors级别的后置处理器,如果有则通过责任链模式调用这些后置处理器的postProcessAfterInstantiation方法



这里InstantiationAwareBeanPostProcessor会在属性注入之前,有最后一次机会去修改bean的属性值,此处也可以决定是否后续的填充步骤


continueWithPropertyPopulation = false;


// 如果上面设置continueWithPropertyPopulation = false,表明用户可能已经自己填充了
// bean的属性,不需要Spring帮忙填充了。此时直接返回即可
if (!continueWithPropertyPopulation) {
   return;
}

接下来来到:

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);


pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝,获取BeanDefinition里面为Bean设置上的属性值

24.png

返回给pvs的是mbd.getPropertyValues()方法的返回值,


public MutablePropertyValues getPropertyValues() {
   if (this.propertyValues == null) {
      this.propertyValues = new MutablePropertyValues();
   }
   return this.propertyValues;
}

MutablePropertyValues类

25.png


bean的属性解析主要就是和这个类打交道的


回到populateBean方法里,第一次解析 pvs 值为空,此时就来到脑图中的第二步,按照名字 or 类型对bean进行自动装配

int resolvedAutowireMode = mbd.getResolvedAutowireMode();

返回结果是0,表示没有配置上自动装配模式,意味着会跳过populateBean的自动装配逻辑。



之前介绍postProcessMergedBeanDefinition方法时,被@Value和@Autowired标记的成员变量已经被标记出来了,只差将其注入到bean实例里了,因此就没必要再走一遍解析了,所以就没必要执行if中的逻辑了。


if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
   // Add property values based on autowire by name if applicable.
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
   }
   // Add property values based on autowire by type if applicable.
   if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
   }
   pvs = newPvs;
}

可以看一看上面两种注入方法的逻辑。


autowireByName:


protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
   // 获取要注入的非简单类型的属性名称
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   for (String propertyName : propertyNames) {
      // 检测是否存在与propertyName相关的bean或BeanDefinition.
      // 若存在,则调用BeanFactory.getBean方法获取bean实例
      if (containsBean(propertyName)) {
         // 从容器中获取相应的bean实例
         Object bean = getBean(propertyName);
         // 将解析出的bean存入到属性值列表pvs中
         pvs.add(propertyName, bean);
         // 注册依赖关系
         registerDependentBean(propertyName, beanName);
         if (logger.isTraceEnabled()) {
            logger.trace("Added autowiring by name from bean name '" + beanName +
                  "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                  "' by name: no matching bean found");
         }
      }
   }
}


先获取非简单类型的属性名称,再根据获取出来的属性名称去依次调用容器的getBean方法获取属性名对应的bean实例,最后将获取到的bean实例连同属性的名称添加到属性列表pvs中,再将bean的依赖关系通过registerDependentBean方法给注册起来。



进入unsatisfiedNonSimpleProperties方法里:


/**
 * 获取非简单类型属性的名称,且该属性未被配置在配置文件中,如下例:将属性明确写在bean里面了,就不算自动装配
 * <bean class="org.springframework.aop.framework.ProxyFactoryBean">
 *        <property name="target">
 *            <ref parent="accountService"/>
 *         </property>
 * </bean>
 *
 * Spring认为的“简单类型“属性有哪些,如下:
 * 1. CharSequence接口的实现类,比如String
 * 2. Enum
 * 3. Date
 * 4. URI/URL
 * 5. Number的继承类,比如Integer/Long
 * 6. byte/short/int...等基本类型
 * 7. Locale
 * 8.以上所有类型的数组形式
 *
 * 
 * @param mbd
 * @param bw
 * @return
 */
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
   Set<String> result = new TreeSet<>();
   PropertyValues pvs = mbd.getPropertyValues();
   PropertyDescriptor[] pds = bw.getPropertyDescriptors();
   for (PropertyDescriptor pd : pds) {
      if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
            !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
         result.add(pd.getName());
      }
   }
   return StringUtils.toStringArray(result);
}


autowireByType:


protected void autowireByType(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
   // 获取的属性类型转换器
   TypeConverter converter = getCustomTypeConverter();
   if (converter == null) {
      converter = bw;
   }
   // 用来存放解析的要注入的属性名
   Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
   // 获取要注入的属性名称(非简单属性(8种原始类型、字符、URL等都是简单属性))
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   for (String propertyName : propertyNames) {
      try {
         // 获取指定属性名称的属性Descriptor(Descriptor用来记载属性的getter setter type等情况)
         PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
         // Don't try autowiring by type for type Object: never makes sense,
         // even if it technically is a unsatisfied, non-simple property.
         // 不对Object类型的属性进行装配注入,技术上没法实现,并且没有意义
         // 即如果属性类型为Object,则忽略,不做解析
         if (Object.class != pd.getPropertyType()) {
            // 获取属性的setter方法
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            // Do not allow eager init for type matching in case of a prioritized post-processor.
            // 对于继承了PriorityOrdered的post-processor,不允许立即初始化(热加载)
            boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
            // 创建一个要被注入的依赖描述,方便提供统一的访问
            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
            // 根据容器的BeanDefinition解析依赖关系,返回所有要被注入的Bean实例
            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
            if (autowiredArgument != null) {
               // 将解析出的bean存入到属性值列表pvs中
               pvs.add(propertyName, autowiredArgument);
            }
            for (String autowiredBeanName : autowiredBeanNames) {
               // 注册依赖关系
               registerDependentBean(autowiredBeanName, beanName);
               if (logger.isTraceEnabled()) {
                  logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                        propertyName + "' to bean named '" + autowiredBeanName + "'");
               }
            }
            // 清除已注入属性的记录
            autowiredBeanNames.clear();
         }
      }
      catch (BeansException ex) {
         throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
      }
   }
}


首先也是获得非简单类型属性名称:

 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);

然后再根据属性名获取属性描述符PropertyDescriptor:

PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);


然后根据属性描述符去获取方法参数对象MethodParameter:


MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);

之后再根据方法参数对象去获取依赖描述符对象DependencyDescriptor:


DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);


进入PropertyDescriptor:


26.png


主要就是用来描述bean里的主要属性,可以通过它获取到该属性的getter或setter


回到autowireByType,


MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);

就是获得属性setter方法实例,保存到MethodParameter实例中,该实例是封装setter的,方便后续注入,DependencyDescriptor描述要注入的依赖

27.png


InjectionPoint是用来描述注入点的,比如boyfriend中的girlfriend就是一个注入点,girlfriend的类型、setter、注解标签这些信息都可以通过InjectionPoint来获取,DependencyDescriptor除了上述的功能外,还保存了一些额外的信息,比如:依赖是否必要


public boolean isRequired() {
   if (!this.required) {
      return false;
   }
   if (this.field != null) {
      return !(this.field.getType() == Optional.class || hasNullableAnnotation() ||
            (KotlinDetector.isKotlinReflectPresent() &&
                  KotlinDetector.isKotlinType(this.field.getDeclaringClass()) &&
                  KotlinDelegate.isNullable(this.field)));
   }
   else {
      return !obtainMethodParameter().isOptional();
   }
}


是否是延迟加载的:


public boolean isEager() {
   return this.eager;
}


相关的一些嵌套级别:

public void increaseNestingLevel() {
   this.nestingLevel ++;
   this.resolvableType = null;
   if (this.methodParameter != null) {
      this.methodParameter = this.methodParameter.nested();
   }
}

回到autowireByType,获取到DependencyDescriptor之后就可以进行属性对应的值的解析了


// 根据容器的BeanDefinition解析依赖关系,返回所有要被注入的Bean实例
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);


autowiredArgument是属性的值,并将其与属性名一起添加到属性列表中


pvs.add(propertyName, autowiredArgument);

之后再注册一下bean之间的依赖关系


registerDependentBean(autowiredBeanName, beanName);


毕竟不是所有的依赖关系都是在配置里显式标注的。注册完成后就完成了该方法

相关文章
|
14天前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
65 29
|
11天前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
29 3
|
13天前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
23天前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
13天前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
21天前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
1月前
|
机器学习/深度学习 自然语言处理 算法
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
145 0
|
3月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2月前
|
Kubernetes Linux 虚拟化
入门级容器技术解析:Docker和K8s的区别与关系
本文介绍了容器技术的发展历程及其重要组成部分Docker和Kubernetes。从传统物理机到虚拟机,再到容器化,每一步都旨在更高效地利用服务器资源并简化应用部署。容器技术通过隔离环境、减少依赖冲突和提高可移植性,解决了传统部署方式中的诸多问题。Docker作为容器化平台,专注于创建和管理容器;而Kubernetes则是一个强大的容器编排系统,用于自动化部署、扩展和管理容器化应用。两者相辅相成,共同推动了现代云原生应用的快速发展。
394 11
|
2月前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
86 0

推荐镜像

更多