Springboot扩展点之BeanFactoryPostProcessor

本文详细介绍了Spring Boot中的BeanFactoryPostProcessor扩展点的工作原理和实现方式,包括如何利用该扩展点对BeanDefinition进行修改,以及其在Bean生命周期中的位置。
部署运行你感兴趣的模型镜像

Springboot扩展点系列实现方式、工作原理集合:

Springboot扩展点之ApplicationContextInitializer

Springboot扩展点之BeanFactoryPostProcessor

Springboot扩展点之BeanDefinitionRegistryPostProcessor

Springboot扩展点之BeanPostProcessor

Springboot扩展点之InstantiationAwareBeanPostProcessor

Springboot扩展点之SmartInstantiationAwareBeanPostProcessor

Springboot扩展点之ApplicationContextAwareProcessor

Springboot扩展点之@PostConstruct

Springboot扩展点之InitializingBean

Springboot扩展点之SmartInitializingSingleton

Springboot扩展点之CommandLineRunner和ApplicationRunner

Springboot扩展点之FactoryBean

Springboot扩展点之DisposableBean

Springboot扩展点系列之终结篇:Bean的生命周期

1.功能特性

  1. BeanFactoryPostProcessor的执行是Spring Bean生命周期非常重要的一部分;

  1. BeanFactory级别的后置处理器,在Spring生命周期内,org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory只会执行一次;

  1. 允许在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且可以根据需要进行修改;

2.实现方式

  1. 定义一个Dog类,name属性默认为“旺财”,颜色默认为“黑色”;

@Data
@Component
public class Dog {
    private String name="旺财";
    private String color="黑色";
}
  1. 定义一个实现类(MyBeanFactoryPostProcessor),实现org.springframework.beans.factory.config.BeanFactoryPostProcessor接口,重写postProcessBeanFactory()方法,并Dog类的属性name修改为“狗蛋”;并用@Component注解标记BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor);

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被执行");
        ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog"))  ;
        MutablePropertyValues propertyValues = dog.getPropertyValues();
        propertyValues.addPropertyValue("name", "狗蛋儿");
        log.info("修改Dog的BeanDefinition对象中的name属性为狗蛋儿");
    }
}
  1. 编写单元测试验证结果;

@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Dog dog = ((Dog) context.getBean("dog"));
        log.info(dog.getName());
        Assert.isTrue(dog.getName().equals("狗蛋儿"), "属性修改失败");
    }
}
  1. 验证结果表明,自定义的BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor),可以在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且根据需要进行修改,那么自定义的BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor)的工作原理是什么呢?BeanFactoryPostProcessor接口的实现类是什么时候实例化的?MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被调用的?接着往下看。

3.工作原理

3.1BeanFactoryPostProcessor接口的实现类是什么时候实例化的?

  1. BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor)被@Component标记,在窗口启动的时候会被封装成BeanDefinition对象注册到容器中;

  1. PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法被执行时,会按照类型从Spring容器中找到所有BeanFactoryPostProcessor类型的实现类的名称;

  1. 在上一步中得到所有BeanFactoryPostProcessor类型的实现类的名称的名称后,再循环一次,来对BeanFactoryPostProcessor的实现类进行实例化 (beanFacotry.getBean()去获取MyBeanFactoryPostProcessor的实例,如果获取不到,就创建一个);

3.2MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被调用的?

  1. 在单元测试中构建了一个AnnotationConfigApplicationContext对象,AnnotationConfigApplicationContext的构造方法如下:

public AnnotationConfigApplicationContext(String... basePackages) {
   this();
   scan(basePackages);
   refresh();
}
  1. 从上面的AnnotationConfigApplicationContext的构造方法中,可以看到又调用了refresh(),这里实际最终被调用的是org.springframework.context.support.AbstractApplicationContext#refresh(),这个方法也是Spring容器启动的关键方法,在分析Spring相关的源码时会经常碰到。

  1. AbstractApplicationContext#refresh()中,调用org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors方法才正式开始了BeanFactoryPostProcessor接口的所有实现类的postProcessBeanFactory()方法调用;

  1. 跟着AbstractApplicationContext#invokeBeanFactoryPostProcessors方法进去,会发现这里只是一个入口,实际承担调用执行任务的是org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法;

  1. 跟着PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法进去后,会发现里面真的是别有洞天,很容易迷路(牢牢带着自己的问题分析源码找答案,不要被除自己问题以外的东西迷了眼,一定会柳暗花明),另外org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor的实现类的调用也在这个方法,所以这个方法的含金量很高,那就单独拎出来仔细分析一下,建议debug一步一步看,多看几遍就能明白,其实也很简单,唯一的难点就是这个方法有点长,需要多点耐心和时间。

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   //之所以说这个方法的含金量很高,
   //是因为在这个方法里是先执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法; 
   //然后才接着执行BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法
   //这两个接口很表面上看很类似,实际在执行的时机和功能上是有明显区别的
   Set<String> processedBeans = new HashSet<>();
   //AnnotationConfigApplicationContext继承于GenericApplicationContext,
   //而GenericApplicationContext又实现了BeanDefinitionRegistry接口
   //所以这里会进入if语句中
   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        //这里提前执行的BeanFactoryPostProcessor,是在准备上下文环境时,发布了ApplicationPreparedEvent事件;
        //触发监听器,通过AbstractApplicationContext#addBeanFactoryPostProcessor注册进来的;
        //这里并不是这次要重点分析的内容,可以先跳过这; 
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }
         else {
            regularPostProcessors.add(postProcessor);
         }
      }
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
      // 从32行到72行,是在执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法;
      //执行的过程也是有点小区折的,分三步,第一,执行实现了PriorityOrdered接口的实现类.
      String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      // 第二,执行实现了Ordered接口的实现类;
      postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      //第三,执行剩下其他的BeanDefinitionRegistryPostProcessor实现类;
      boolean reiterate = true;
      while (reiterate) {
         reiterate = false;
         postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName)) {
               currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
               processedBeans.add(ppName);
               reiterate = true;
            }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();
      }
      // BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,
      //所以这部分实现类的postProcessBeanFactory()会提前执行
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      //第26行,非BeanDefinitionRegistryPostProcessor类型的BeanFactoryPostProcessor实现类会在这执行
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   } else {
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }
   //BeanDefinitionRegistryPostProcessor接口的实现类上面已执行执行完了
   //下面开始准备执行BeanFactoryPostProcessor接口的实现类
   String[] postProcessorNames =
         beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
   // 正式执行前,把BeanFactoryPostProcessor接口的实现类分成了三类,
   //分别是实现了PriorityOrdered接口,实现了Ordered接口,其他;
   List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   for (String ppName : postProcessorNames) {
      if (processedBeans.contains(ppName)) {
         // skip - already processed in first phase above
      }
      else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
         priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }
   // 分好类,第一,先执行实现了PriorityOrdered接口的实现类; 
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
   // 第二,执行实现了Ordered接口的实现类; 
   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
   //第三,执行未实现上面两个接口的实现类,自定义的MyBeanFactoryPostProcessor就是在这里被执行的
   //其实,也很简单的,和BeanDefinitionRegistryPostProcessor接口的实现类的执行过程类似; 
   List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String postProcessorName : nonOrderedPostProcessorNames) {
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
   beanFactory.clearMetadataCache();
}

3.3调用时序图

这里我画了一个时序图,可以更直观的看到整个调用过程,也可以照着这个图,一步一步debug来了解整个过程;

3.4postProcessBeanFactory()postProcessBeanDefinitionRegistry()

通过分析PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法,postProcessBeanFactory()与postProcessBeanDefinitionRegistry()的区别已经很明显了,这里再总结一下(总结的有不准的地方,还请小伙伴在评论区告诉我,一块进步):

  1. BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanDefinitionRegistry方法要优先于BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法执行;

  1. postProcessBeanDefinitionRegistry方法形参是BeanDefinitionRegistry,postProcessBeanFactory方法的形参是ConfigurableListableBeanFactory,在功能上会有一些区别;需要注意的是DefaultListableBeanFactory实现了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口;

  1. BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,关于BeanDefinitionRegistryPostProcessor可以移步这里:Springboot扩展点之BeanDefinitionRegistryPostProcessor

4.应用场景

对敏感信息的解密处理,比如数据库连接信息加密和解密:在实际的业务开发中,在配置文件中明文配置mysq,redis的密码实际上是不安全的,需要配置加密后的密码信息; 但是把加密后的密码信息注入的数据源中,去连接mysql数据库肯定会连接异常,因为mysql并不知道你的加密方式和加密方法。这就会产生一个需求:需要在配置文件中配置的数据库信息是加密的,但是在把密码信息注入数据源前在程序里解密处理。

BeanFactoryPostProcessor正好可以解决这个问题,在真正使用到数据源去连接数据库前,读取到加密信息,进行解密处理,再用解密后的信息替换掉Spring容器中加密信息。

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

<think>我们正在讨论SpringBoot中的BeanFactoryPostProcessor。根据用户的问题和提供的引用,我们需要解释BeanFactoryPostProcessor的作用及使用场景。注意,用户之前询问的是BeanPostProcessor,现在转向BeanFactoryPostProcessor,因此要明确区分两者。根据引用[1][2][3][5]:-BeanFactoryPostProcessorSpring框架的一个扩展接口,它允许在Spring容器加载了Bean定义(BeanDefinition)之后,但在Bean实例化之前,对Bean的定义进行修改。-与BeanPostProcessor(作用于Bean实例化后的生命周期)不同,BeanFactoryPostProcessor作用于容器级,修改的是Bean的元数据(BeanDefinition)。作用:1.修改Bean定义:可以修改Bean的属性值、构造函数参数值,甚至替换Bean定义(例如改变Bean的类或作用域)[^1][^5]。2.注册新的Bean定义:通过BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessor的子接口)可以动态注册新的Bean定义[^2]。3.处理配置占位符:如PropertyPlaceholderConfigurer(已过时,现在推荐使用PropertySourcesPlaceholderConfigurer)用于解析属性文件中的占位符,并将其注入到Bean定义中[^1]。4.条件化注册Bean:在SpringBoot中,很多自动配置类使用BeanFactoryPostProcessor来根据条件动态调整Bean定义。使用场景:-属性占位符解析:将外部配置(如application.properties)中的值注入到Bean定义的占位符中[^1]。-配置类处理:SpringBoot的@Configuration类处理过程中,会使用BeanFactoryPostProcessor(如ConfigurationClassPostProcessor)来解析配置类,注册其中定义的Bean[^3]。-中间件集成:在集成第三方库时,可能需要动态修改Bean定义。例如,在MyBatis-Spring集成中,MapperScannerConfigurer(实现了BeanDefinitionRegistryPostProcessor)扫描指定包并注册Mapper接口的Bean定义[^2]。-性能调优:引用[4]虽然讲的是性能调优,但BeanFactoryPostProcessor的使用也可能涉及性能优化,例如通过减少不必要的Bean定义来优化容器启动速度。实现机制:-Spring容器启动时,在创建BeanFactory之后,会调用所有BeanFactoryPostProcessor的postProcessBeanFactory方法(对于BeanDefinitionRegistryPostProcessor,会先调用其postProcessBeanDefinitionRegistry方法)[^2][^3]。-这些处理器按优先级执行(通过Ordered接口或@Order注解控制)。示例(引用[5]):在applyPropertyValue方法中,通过BeanFactory获取BeanDefinition,然后修改其属性值。这展示了如何修改Bean定义。总结:BeanFactoryPostProcessorSpringBoot中用于在容器初始化阶段修改Bean定义的核心扩展点,常用于属性解析、动态注册Bean等场景[^1][^2][^3][^5]。现在,按照要求生成相关问题。</think>### Spring BootBeanFactoryPostProcessor的作用及使用场景 `BeanFactoryPostProcessor`是Spring Boot框架的核心扩展接口,作用于**容器初始化阶段**,主要用于修改或增强Bean的元数据(BeanDefinition)。它与`BeanPostProcessor`(作用于Bean实例化阶段)形成互补,共同构成Spring容器的扩展机制[^1][^3][^5]。 --- #### 一、核心作用 1. **修改Bean定义(BeanDefinition)** 在Bean实例化**之前**,可动态修改Bean的属性值、构造函数参数、作用域等元数据[^1][^5]。 ```java public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { BeanDefinition bd = beanFactory.getBeanDefinition("myBean"); bd.getPropertyValues().add("timeout", 5000); // 修改属性值 } ``` 2. **动态注册新Bean** 通过子接口`BeanDefinitionRegistryPostProcessor`(继承自`BeanFactoryPostProcessor`)可注册新Bean定义[^2][^3]。 ```java public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { registry.registerBeanDefinition("newBean", new RootBeanDefinition(NewService.class)); } ``` 3. **处理配置占位符** 如`PropertySourcesPlaceholderConfigurer`解析`${}`占位符,将外部配置(如`application.properties`)注入Bean定义[^1][^5]。 4. **条件化Bean注册** 结合`@Conditional`注解实现条件化配置,例如根据环境变量动态启用/禁用Bean[^3]。 --- #### 二、典型使用场景 1. **外部配置集成** - 解析属性文件(如`application.yml`)并应用到Bean定义中 - 示例:`PropertyPlaceholderConfigurer`(已过时)或`PropertySourcesPlaceholderConfigurer`[^1] 2. **自动配置类处理** Spring Boot自动配置的核心机制: - `ConfigurationClassPostProcessor`扫描`@Configuration`类 - 解析`@Bean`、`@Import`等注解,注册Bean定义[^3][^5] 3. **中间件集成** - 第三方库(如MyBatis、Hibernate)通过`BeanDefinitionRegistryPostProcessor`动态注册组件 - 示例:MyBatis的`MapperScannerConfigurer`扫描Mapper接口[^2] 4. **性能优化** - 预加载时修改Bean定义,减少运行时开销 - 示例:缓存Bean元数据、延迟初始化配置[^4] 5. **安全增强** - 加密敏感属性(如数据库密码),在Bean定义阶段解密 ```java bd.getPropertyValues().add("password", decrypt(encryptedValue)); ``` --- #### 三、执行时机与机制 1. **生命周期阶段** ```mermaid graph LR A[加载Bean定义] --> B[执行BeanFactoryPostProcessor] B --> C[实例化Bean] C --> D[执行BeanPostProcessor] ``` 2. **执行顺序** - 优先执行`BeanDefinitionRegistryPostProcessor`(子接口) - 再执行普通`BeanFactoryPostProcessor` - 顺序可通过`Ordered`接口或`@Order`注解控制[^2][^3] 3. **源码关键点** - 入口:`AbstractApplicationContext.refresh()`中的`invokeBeanFactoryPostProcessors()` - 核心实现:`PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()`[^5] --- #### 四、与BeanPostProcessor的区别 | **特性** | BeanFactoryPostProcessor | BeanPostProcessor | |------------------------|---------------------------------------------|---------------------------------------| | **作用阶段** | Bean实例化前(修改Bean定义) | Bean实例化后(修改Bean实例) | | **操作对象** | BeanDefinition(元数据) | Bean实例对象 | | **典型应用** | 占位符解析、动态注册Bean | 依赖注入、AOP代理、生命周期回调 | | **子接口扩展** | BeanDefinitionRegistryPostProcessor | InstantiationAwareBeanPostProcessor | > 引用说明: > [^1]: 修改Bean定义的核心机制,如属性占位符解析 > [^2]: 子接口`BeanDefinitionRegistryPostProcessor`的动态注册能力 > [^3]: 在Spring Boot自动配置中的实际应用 > [^5]: 源码级修改Bean定义的示例(如`applyPropertyValue`方法)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡夫贩夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值