spring源码学习 populateBean()源码分析

本文详细解读了Spring框架中populateBean方法的工作原理,涉及属性注入过程、合成类的概念、自动装配模式(如按名称和类型)、依赖检查机制以及BeanPostProcessor的使用。这个方法在SpringBean的生命周期管理中扮演着关键角色。
摘要由CSDN通过智能技术生成

概述

populateBean()方法位于的AbstractAutowireCapableBeanFactory类中,作用是将属性值填充到Bean对象中。 即属性注入阶段的实现方法。spring通过该方法,实现属性注入,在bean的实例化阶段,完成属性注入操作。

源码分析

先明确几个概念。

第一个,合成类的概念。

合成类是什么?

合成类(synthetic class)是由编译器或运行时生成的类,而不是由开发人员显式定义的类。合成类通常用于支持特定的编译器优化、字节码增强或框架功能。

在 Java 编程中,合成类是指由编译器自动生成的类,用于支持一些特殊的语言特性或实现机制。例如,匿名内部类就是一种合成类。当我们在代码中创建一个匿名内部类时,编译器会自动生成一个合成类来表示该匿名内部类。

合成类还常用于字节码增强技术,例如在 AOP 框架中,会根据切面定义生成合成类来实现横切逻辑的织入。

合成类的特点是它们不是开发人员直接编写的源代码,而是由编译器或运行时生成的。它们可能具有特殊的命名规则、访问修饰符或其他属性,以区别于开发人员定义的类。

在 Java 反射中,可以使用 isSynthetic() 方法来判断一个类是否为合成类。该方法返回一个布尔值,指示给定的类是否为合成类。如果一个类被标记为合成类,通常意味着它是由编译器或运行时生成的,而不是开发人员直接定义的。

 第二个,自动装配模式有哪些?

resolvedAutowireMode有哪些?

resolvedAutowireMode是用于获取解析后的自动装配模式的方法。在 Spring 框架中,自动装配模式可以通过autowire属性或者@Autowired注解来指定。通过mbd.getResolvedAutowireMode()来获取resolvedAutowireMode的值。

resolvedAutowireMode的值是整数值,有以下几种:

0:不进行自动装配。

1:按照属性名进行自动装配。

2:按照属性类型进行自动装配。

3:按照构造函数参数类型进行自动装配。

4:自动检测模式,根据属性类型和名称进行自动装配。

第三个,spring中的依赖检查模式有哪些?

 spring中的依赖检查模式有哪些?

通过mbd.getDependencyCheck()获取依赖检查模式。在 Spring 框架中,可以通过 dependency-check 属性或者 @Autowired 注解的 required 属性来指定依赖检查模式。

依赖检查模式有以下三种:

none:表示不进行依赖检查。

objects:表示对对象类型的依赖进行检查。

simple:表示对简单类型的依赖进行检查。

好,介绍完这三个概念,开始看源码。

populateBean()方法源码

/**
 * Populate the bean instance in the given BeanWrapper with the property values
 * from the bean definition.
 * @param beanName the name of the bean bean的名称
 * @param mbd the bean definition for the bean bean的定义信息
 * @param bw the BeanWrapper with bean instance bean实例的包装类
 */
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   // 判断bean是否有属性
   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.
         // 跳过null实例的属性填充阶段。
         return;
      }
   }

   // 判断是否是record类,record类是不能注入属性的
   if (bw.getWrappedClass().isRecord()) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
      }
      else {
         // Skip property population phase for records since they are immutable.
         // 跳过记录的属性填充阶段,因为它们是不可变的。
         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.
   // 在设置属性之前,让任何InstantiationAwareBeanPostProcessors都有机会修改bean的状态。例如,这可以用于支持现场注入的样式。
   // 这里是一个扩展点,执行InstantiationAwareBeanPostProcessor中的postProcessAfterInstantiation()方法,InstantiationAwareBeanPostProcessor
   // 也是BeanPostProcessor的一个子类
   // mbd.isSynthetic()判断给定的beanDefinition是否是一个合成类
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            return;
         }
      }
   }

   // mbd.getPropertyValues() 方法用于获取给定的 mbd 对象中定义的属性值。
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   // mbd.getResolvedAutowireMode() 是用于获取解析后的自动装配的模式
   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;
   }
   // 对非autowiring的属性进行依赖注入处理,也就是通过BeanPostProcessor来注入
   // 判断此factory是否有InstantiationAwareBeanPostProcessor
   if (hasInstantiationAwareBeanPostProcessors()) {
      // 上一步pvs已经赋值了newPvs
      // 如果该对象不是autowiring,那么newPvs是空的,psv也就是空的
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      // 这里是一个扩展点,执行InstantiationAwareBeanPostProcessor中的postProcessProperties()方法
      // bp.postProcessProperties会另外介绍,他的作用是注入属性
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         // 如果结果为空,会调用postProcessPropertyValues()方法(已过时)
         if (pvsToUse == null) {
            return;
         }
         pvs = pvsToUse;
      }
   }

   // 进行依赖检查
   // 只要mbd中配置的依赖检查不是none(不检查),就进入检查流程
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
   if (needsDepCheck) {
      // 获取需要进行依赖检查的属性
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      // 进行依赖检查
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      // 这里是真正的将属性注入到bean中,前面只是将属性保存到了pvs变量中
      // 具体源码另开一篇文章
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

populateBean()方法的作用是将属性值填充到Bean对象中。 即属性注入阶段的实现方法。

在Spring框架中,当创建一个Bean实例后,需要将配置文件或注解中定义的属性值赋值给该实例的属性。populateBean()方法就是用来完成这个属性填充的过程。

该方法接收三个参数:beanName表示Bean的名称,mbd表示Bean的元数据描述,bean表示要填充属性的Bean对象。

在populateBean()方法中,首先会获取Bean的属性定义,包括属性名称、类型、值等信息。然后根据这些属性定义,通过反射机制将属性值填充到Bean对象的对应属性中。

属性值的来源可以是配置文件中的属性值,也可以是通过注解指定的属性值。Spring会根据属性定义的信息,从配置文件或注解中获取对应的属性值,并将其赋值给Bean对象的属性。

通过调用populateBean()方法,Spring能够自动将属性值填充到Bean对象中,使得Bean对象具备了正确的属性值,可以在后续的业务逻辑中正常使用。

 这里用到了两个方法,autowireByName()和autowireByType(),会另开一篇文章解释这两个方法。

spring源码学习 autowireByName()和autowireByType()

真正注入属性的applyPropertyValues()方法,也会另开一篇文章解释。

spring源码学习 applyPropertyValues()方法

hasInstantiationAwareBeanPostProcessors()方法源码

/**
 * Return whether this factory holds a InstantiationAwareBeanPostProcessor
 * that will get applied to singleton beans on creation.
 * 从缓存中返回此工厂是否持有InstantiationAwareBeanPostProcessor
 * 该处理器将在创建时应用于单例bean。
 * @see #addBeanPostProcessor
 * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
 */
protected boolean hasInstantiationAwareBeanPostProcessors() {
   return !getBeanPostProcessorCache().instantiationAware.isEmpty();
}

filterPropertyDescriptorsForDependencyCheck()源码

/**
 * Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
 * excluding ignored dependency types or properties defined on ignored dependency interfaces.
 * 从给定的BeanWrapper中提取一组经过过滤的PropertyDescriptor
 * 排除被忽略的依赖项类型或在被忽略的依存关系接口上定义的属性
 * 最终返回的是需要检查的属性
 * 至于哪些属性被过滤,哪些被保留,取决于RootBeanDefinition的allowCaching
 * @param bw the BeanWrapper the bean was created with
 * @param cache whether to cache filtered PropertyDescriptors for the given bean Class
 * @return the filtered PropertyDescriptors
 * @see #isExcludedFromDependencyCheck
 * @see #filterPropertyDescriptorsForDependencyCheck(org.springframework.beans.BeanWrapper)
 */
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw, boolean cache) {
   // 首先从缓存中获取要过滤的属性
   PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
   // 如果缓存中没有,就从bean中获取
   if (filtered == null) {
      filtered = filterPropertyDescriptorsForDependencyCheck(bw);
      if (cache) {
         // 保存到缓存中
         PropertyDescriptor[] existing =
               this.filteredPropertyDescriptorsCache.putIfAbsent(bw.getWrappedClass(), filtered);
         if (existing != null) {
            filtered = existing;
         }
      }
   }
   return filtered;
}

该方法用于过滤属性描述符以进行依赖检查。

在 Spring 的自动装配过程中,当创建一个 bean 实例时,需要对其属性进行自动装配。在自动装配属性时,Spring 需要确定哪些属性需要进行依赖检查,以确保它们的依赖关系被正确设置。

filterPropertyDescriptorsForDependencyCheck() 方法的作用就是根据给定的 BeanWrapper 对象 bw 和 mbd.allowCaching 参数,过滤出需要进行依赖检查的属性描述符。

具体来说,该方法会遍历 bw 中的所有属性描述符,并根据以下条件进行过滤:

  1. 如果 mbd.allowCaching 为 true,则只保留可读属性(即具有读取方法)。

  2. 如果 mbd.allowCaching 为 false,则保留可读可写属性(即具有读取方法和写入方法)。

根据上述条件,方法会返回一个经过过滤的属性描述符数组,其中只包含需要进行依赖检查的属性。

通过这个方法,Spring 可以根据配置的 allowCaching 属性过滤出需要进行依赖检查的属性,以确保它们的依赖关系被正确设置。这是 Spring 自动装配过程中的一部分,用于保证 bean 的依赖关系的正确性。

checkDependencies()源码

/**
 * Perform a dependency check that all properties exposed have been set,
 * if desired. Dependency checks can be objects (collaborating beans),
 * simple (primitives and String), or all (both).
 * 执行依赖性检查,确保所有暴露的属性都已设置
 * 如果需要的话。依赖性检查可以是对象(协作bean)
 * simple(基元和String)或all(两者)。
 * @param beanName the name of the bean bean名称
 * @param mbd the merged bean definition the bean was created with bean定义信息
 * @param pds the relevant property descriptors for the target bean 属性描述数组
 * @param pvs the property values to be applied to the bean 属性值
 * @see #isExcludedFromDependencyCheck(java.beans.PropertyDescriptor)
 */
protected void checkDependencies(
      String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, @Nullable PropertyValues pvs)
      throws UnsatisfiedDependencyException {

   // 获取依赖检查模式
   int dependencyCheck = mbd.getDependencyCheck();
   // 逐个属性进行校验
   for (PropertyDescriptor pd : pds) {
      // 检查该属性的setter方法是否存在,且属性值中不包含它,避免重复检查
      if (pd.getWriteMethod() != null && (pvs == null || !pvs.contains(pd.getName()))) {
         // 判断该类型是否是基本类型或字符串
         boolean isSimple = BeanUtils.isSimpleProperty(pd.getPropertyType());
         boolean unsatisfied = (dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_ALL) ||
               (isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE) ||
               (!isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
         if (unsatisfied) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, pd.getName(),
                  "Set this property value or disable dependency checking for this bean.");
         }
      }
   }
}

校验逻辑如下:

  • 如果 dependencyCheck 的值为 AbstractBeanDefinition.DEPENDENCY_CHECK_ALL,表示要检查所有的依赖关系。

  • 如果 isSimple 为 true,并且 dependencyCheck 的值为 AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE,表示只检查简单属性的依赖关系。

  • 如果 isSimple 为 false,并且 dependencyCheck 的值为 AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS,表示只检查非简单属性(即对象类型)的依赖关系。

  • 如果上述条件满足其中之一,表示存在未满足的依赖关系,将抛出 UnsatisfiedDependencyException 异常,其中包含了相关的错误信息。

该方法的作用是在 bean 的创建过程中检查属性的依赖关系,并根据依赖检查模式进行判断。如果存在未满足的依赖关系,就会抛出异常。这样可以确保 bean 的依赖关系被正确设置,从而保证应用程序的正确运行。

总结

populateBean()方法的作用是将属性值填充到Bean对象中,在属性注入阶段发挥作用。

他的执行流程是这样的:

  1. 判断该bean是否拥有属性,没有属性则结束注入流程

  2. 判断是否是record类型,是record类型则结束注入流程

  3. 执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()方法

  4. 获取 beanDefintion中定义的属性值

  5. 获取自动装配模式,决定是按名称注入还是按类型注入

  6. 如果还有通过InstantiationAwareBeanPostProcessor注入的属性,则执行InstantiationAwareBeanPostProcessor.postProcessProperties()方法来注入属性

  7. 进行依赖检查

  8. 将注入属性保存到bean中

populateBean()是beanFactory中非常重要的一个方法,他也是spring生命周期中非常重要的一环,它是属性注入阶段的核心方法。同时,BeanPostProcessor中的两个方法,也在populateBean()中触发。

  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值