Spring中Bean实例化过程中的populateBean方法

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Spring中Bean实例化过程中的populateBean方法

关联博文

Spring后置处理器中的InstantiationAwareBeanPostProcessor详解

Spring中Bean实例化过程中的initializeBean方法

Spring中Bean实例化过程中的populateBean方法

Spring中@Autowired与@Resource自动注入实现原理

这是bean实例化后非常重要的一个环节。用bean定义中的属性值填充给定BeanWrapper中的bean实例,也就是属性赋值过程。这里会涉及到成员的依赖注入解析过程,也会涉及到循环依赖。

本文环境:SpringBoot+mybatisplus。


如下所示,在populateBean(beanName, mbd, instanceWrapper);方法执行前我们的fileController实例:

// 如下是我们定义的成员
private static  final Logger logger= LoggerFactory.getLogger(FileController.class);
@Autowired
private SysFileService fileService;
@Value("${com.jane.file.baseFilePath}")
private String baseFilePath;
@Value("${com.jane.configjson.baseFilePath}")
private String configJsonPath;
@Autowired
private SysFileMapper fileMapper;
private static  String name="jane";
private   String sex="男";



253896ca79ff4a268f5b3c7e3396c8df.png

接下来我们跟踪分析一下populateBean方法。


【1】方法概览

我们来看一下AbstractAutowireCapableBeanFactory的populateBean方法。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// BeanWrapperImpl内部包含了目标Bean实例 、conversionService
  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.
//在bean 属性被设置前给InstantiationAwareBeanPostProcessors 计划修改bean state
// Synthetic默认为false
  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
          return;
        }
      }
    }
  }
// 从mbd中获取属性值键值对
  PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 判断autoWire类型,进而解析依赖。如果该值为0  则不会执行if逻辑
// 当然你可以选择对autowire进行设置
  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) {
      // 根据Name注入
      autowireByName(beanName, mbd, bw, newPvs);
    }
    // Add property values based on autowire by type if applicable.
    if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    // 根据TYPE注入
      autowireByType(beanName, mbd, bw, newPvs);
    }
    pvs = newPvs;
  }
// 容器中是否有InstantiationAwareBeanPostProcessor
  boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要进行依赖检测
  boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
  PropertyDescriptor[] filteredPds = null;
  if (hasInstAwareBpps) {
    if (pvs == null) {
      pvs = mbd.getPropertyValues();
    }
    // 调用InstantiationAwareBeanPostProcessor 的postProcessProperties方法
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//这里很重要,会触发AutowiredAnnotationBeanPostProcessor实现依赖的解析
        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;
      }
    }
  }
  // 如果需要依赖检测,进行依赖检测
  if (needsDepCheck) {
    if (filteredPds == null) {
      filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    }
    // 进行依赖检查
    checkDependencies(beanName, mbd, filteredPds, pvs);
  }
// 如果pvs不为null,进行赋值
  if (pvs != null) {
    applyPropertyValues(beanName, mbd, bw, pvs);
  }
}


如上代码所示,核心逻辑可以梳理为如下几个步骤:


① 调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation

② 从mbd获取pvs

③ 判断AutowireMode,如果是AUTOWIRE_BY_NAME或者AUTOWIRE_BY_TYPE触发依赖解析;

④ 获取hasInstAwareBpps与needsDepCheck标识;前者判断是否有InstantiationAwareBeanPostProcessor,后者判断是否需要进行依赖检查。

⑥ 如果hasInstAwareBpps为true,则给InstantiationAwareBeanPostProcessor一个机会触发其postProcessProperties(或者postProcessPropertyValues)更新pvs的值。这一步很关键哦,如果resolvedAutowireMode为0,那么我们@Autowired注解的依赖解析就发生在这里。

⑦ 如果④中获取的needsDepCheck标识为true,则进行依赖检查(checkDependencies);

⑧ 如果pvs不为null,则尝试给bean赋值。

【2】方法分析

这里调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation我们不用过于关注,默认实现为true,只在自定义字段注入的时候才需要重写该方法。


如果resolvedAutowireMode为AUTOWIRE_BY_NAME或者AUTOWIRE_BY_TYPE那么就会触发根据名称或者根据类型的依赖解析,本文这里我们不打算进一步分析其细节会在另外博文里面说明。


我们需要关注的是InstantiationAwareBeanPostProcessor的postProcessProperties与postProcessPropertyValues方法。这两个方法十分重要,尤其是前者。如CommonAnnotationBeanPostProcessor与AutowiredAnnotationBeanPostProcessor就是在postProcessProperties方法中处理@Resource与@Autowire的注解,实现依赖解析与注入的。依赖解析的过程也就是getBean的过程,那么这个过程又会涉及到循环依赖。

// 依赖解析的调用栈
doGetBean:245, AbstractBeanFactory 
getBean:202, AbstractBeanFactory 
resolveCandidate:276, DependencyDescriptor 
doResolveDependency:1287, DefaultListableBeanFactory 
resolveDependency:1207, DefaultListableBeanFactory 
inject:640, AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement 
inject:116, InjectionMetadata 
postProcessProperties:399, AutowiredAnnotationBeanPostProcessor 
populateBean:1422, AbstractAutowireCapableBeanFactory 

而postProcessPropertyValues则是一种补偿手段,不过CommonAnnotationBeanPostProcessor与AutowiredAnnotationBeanPostProcessor及InstantiationAwareBeanPostProcessorAdapter均为该方法贴上了“过期”的标识,标明该方法在未来版本将会放弃。


另外,ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor的postProcessProperties方法会为bean设置beanFactory(DefaultListableBeanFactory)。

依赖检查

如下所示基本原则是判断pvs中是否包括pds的属性name,如果不包括那么再进行进一步判断,不满足将会抛出异常。



也就是说,在spring IOC容器中,设计了一个依赖检查特性,通过它spring可以帮助应用检查是否所有的属性都已经被正确设置。在具体使用的时候,应用只需要在Bean定义中设置dependency-check属性来指定依赖检查模式接口。如下所示,这里可以将属性设置为none、simple、object、all四种模式,默认的模式是none

//no dependency check at all.
public static final int DEPENDENCY_CHECK_NONE = 0;
// dependency checking for object references.
public static final int DEPENDENCY_CHECK_OBJECTS = 1;
// dependency checking for "simple" properties.
public static final int DEPENDENCY_CHECK_SIMPLE = 2;
//dependency checking for all properties
public static final int DEPENDENCY_CHECK_ALL = 3;

applyPropertyValues

这个方法就是将前面得到的PropertyValues设置给BeanWrapper,也就是属性赋值的过程。这里会涉及到运行时引用的解析并对list/map/set等集合类型进行处理。


如下所示,最开始得到的PropertyValues pvs为null,默认情况下resolvedAutowireMode为0也不需要进行依赖检查。


InstantiationAwareBeanPostProcessorpostProcessProperties执行完后,那么其所依赖的比如fileSevice、baseFilePath、configJsonPath、fileMapper等均已完成赋值。


本文环境下,为controller实例化,pvs为空。那么pvs什么情况不为空呢?比如为我们的xxxMapper实例化的时候,其将会解析sqlSessionFactory、sqlSessionTemplate放到pvs中。

0 = {PropertyValue@9394} "bean property 'addToConfig'"
1 = {PropertyValue@9395} "bean property 'sqlSessionFactory'"
2 = {PropertyValue@9396} "bean property 'sqlSessionTemplate'"


目录
相关文章
|
18天前
|
XML 安全 Java
|
2天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
26 3
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
16天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
27 1
|
2月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
80 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
34 1
|
2月前
|
存储 安全 Java
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
32 1
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 0
下一篇
DataWorks