• Spring扩展 BeanDefinitionRegistryPostProcessor详解


    1、简介

    2、概念

    2.1 基本介绍

    2.1.1  BeanDefinitionRegistryPostProcessor 它是Spring框架的一个扩展点,用于对Bean定义的注册过程进行干预和定制。

    2.1.2  BeanDefinitionRegistryPostProcessor 它继承BeanFactoryPostProcessor接口,并在其基础上扩展了一个新的方法,即:postProcessBeanDefinitionRegistry()方法。

    2.2 用途

    BeanDefinitionRegistryPostProcessor 在Spring容器初始化时,首先会读取应用程序中的配置文件,并解析出所有的Bean定义,然后将这些Bean定义注册到容器中。

    在这个过程中,BeanDefinitionRegistryProcessor提供了一种机制,允许开发人员在Bean定义注册之前和之后对Bean定义进行自定义处理,例如添加,修改或删除Bean定义等

    2.3 具体原理

    具体来说,BeanDefinitionRegistryPostProcessor提供了以下两个方法:

    2.3.1  postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry):

    该方法在所有Bean定义加载完成之后,Bean实例化之前被调用,允许开发人员对Bean定义进行自定义修改,例如添加,修改或删除Bean定义等。

    2.3.2  postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory):

    该方法是继承自BeanFactoryPostProcessor接口的方法,用于在BeanFactory完成实例化之后对BeanFactory进行后置处理。
    那么我们通过BeanDefinitionRegistryPostProcessor接口,开发人员可以在Spring容器启动时干预Bean的注册过程,从而实现对Bean的自定义处理。

    3、调用demo

    3.1  案例一

    3.1.1  Entity 类 (MyBean)

    1. public class MyBean {
    2. private String message = "Hello, World!";
    3. public String getMessage() {
    4. return message;
    5. }
    6. public void setMessage(String message) {
    7. this.message = message;
    8. }
    9. }

    3.1.2  手写一个接口

    这个接口实现BeanDefinitionRegistryPostProcessor和接口PriorityOrdered,在postProcessBeanDefinitionRegistry方法中对bean的操作进行增删查改

    1. @Component
    2. public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    3. /**
    4. * 重写BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
    5. */
    6. @Override
    7. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    8. // 创建一个RootBeanDefinition实例,该实例对应的BeanClass是MyBean
    9. RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
    10. // 向BeanDefinitionRegistry注册MyBean的BeanDefinition
    11. registry.registerBeanDefinition("myBean", beanDefinition);
    12. // 查询和修改
    13. BeanDefinition myBean = registry.getBeanDefinition("myBean");
    14. System.out.println(myBean);
    15. // 删除
    16. registry.removeBeanDefinition("myBean");
    17. }
    18. /**
    19. * 重写BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
    20. */
    21. @Override
    22. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    23. }
    24. @Override
    25. public int getOrder() {
    26. return 1;
    27. }
    28. }

    3.1.3  启动类

    1. @SpringBootApplication
    2. public class FactorybeanDemoApplication {
    3. public static ConfigurableApplicationContext context ;
    4. public static void main(String[] args) {
    5. context = SpringApplication.run(FactorybeanDemoApplication.class, args);
    6. MyBean bean = context.getBean(MyBean.class);
    7. System.out.println("================"+bean.getMessage()+"===================");
    8. }
    9. }
    • 上述代码会抛出No qualifying bean异常,因为我们把myBean的bd删除了
    1. Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
    2. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    3. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    4. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    5. at java.lang.reflect.Method.invoke(Method.java:498)
    6. at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
    7. Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.factorybean.factorybeandemo.factorybean.test.MyBean' available
    8. at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:343)
    9. at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
    10. at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)
    11. at com.factorybean.factorybeandemo.FactorybeanDemoApplication.main(FactorybeanDemoApplication.java:17)
    12. ... 5 more
    • 注释掉“registry.removeBeanDefinition("myBean");” 就可以执行成功
    1. 2023-10-22 14:43:22.448 INFO 73304 --- [ restartedMain] c.f.f.FactorybeanDemoApplication : Started FactorybeanDemoApplication in 1.333 seconds (JVM running for 1.87)
    2. ================Hello, World!===================

    3.2  案例二

    3.2.1   配置类 (MyPostBeanRegistar)

    1. @Configuration
    2. public class MyPostBeanRegistar implements BeanDefinitionRegistryPostProcessor {
    3. @Override
    4. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    5. System.out.println("postProcessBeanDefinitionRegistry is invoked");
    6. String clzz= Base.class.getName();
    7. for(int i=0;i<2;i++){
    8. if(!beanDefinitionRegistry.containsBeanDefinition(i+""))
    9. ResgistarUtils.registerBeanDefinations(i+"",clzz,beanDefinitionRegistry);
    10. }
    11. }
    12. @Override
    13. public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    14. System.out.println("postProcessBeanFactory is invoked");
    15. }
    16. }

    3.2.2  注册Utils类 (ResgistarUtils)

    1. public class ResgistarUtils {
    2. /**
    3. * 注册工具类方法
    4. * @param className
    5. * @param clzz
    6. * @param beanDefinitionRegistry
    7. */
    8. public static void registerBeanDefinations(String className, String clzz, BeanDefinitionRegistry beanDefinitionRegistry){
    9. /**
    10. * 通过 工厂方法来注入Bean
    11. */
    12. BeanDefinitionBuilder builder= BeanDefinitionBuilder.genericBeanDefinition(MyfactoryBean.class);
    13. builder.addPropertyValue("type",clzz);
    14. builder.addPropertyValue("name",className);
    15. builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
    16. AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    17. if(className.equals("0")) {
    18. beanDefinition.setPrimary(true);
    19. }else{
    20. //beanDefinition.s
    21. }
    22. BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className);
    23. BeanDefinitionReaderUtils.registerBeanDefinition(holder, beanDefinitionRegistry);
    24. }
    25. }

    3.2.3   工厂bean接口实现

    1. public class MyfactoryBean implements FactoryBean {
    2. public Class getType() {
    3. return type;
    4. }
    5. public void setType(Class type) {
    6. this.type = type;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. private Class type;
    15. private String name;
    16. @Override
    17. public Object getObject() throws Exception {
    18. System.out.println("getObject");
    19. if(this.name.equals("0")){
    20. return new TestA();
    21. }else if(this.name.equals("1")){
    22. return new TestB();
    23. }
    24. throw new ClassNotFoundException("not found Base by name=["+name+"]");
    25. }
    26. @Override
    27. public Class getObjectType() {
    28. return type;
    29. }
    30. }
    31. 3.2.4  Entity 类 (Base、TestA、TestB)

      1. public interface Base {
      2. void print();
      3. }
      1. public class TestA implements Base {
      2. public TestA(){
      3. System.out.println("TestA 够着");
      4. }
      5. @Override
      6. public void print() {
      7. System.out.println("testA aaa");
      8. }
      9. }
      1. public class TestB implements Base {
      2. public TestB(){
      3. System.out.println("TestB 够着");
      4. }
      5. @Override
      6. public void print() {
      7. System.out.println("testB bbbb ");
      8. }
      9. }

      3.2.5  测试 Controller 类 (TestController)

      1. @RestController
      2. public class TestController {
      3. @Autowired
      4. Base base1;
      5. // @Autowired
      6. // @Qualifier("1")
      7. @Resource(name = "1")
      8. Base base2;
      9. @GetMapping("/testprint")
      10. public String print(){
      11. base1.print();
      12. base2.print();
      13. return "testprint";
      14. }
      15. }

      3.2.6  启动类

      1. @SpringBootApplication
      2. public class FactorybeanDemoApplication {
      3. public static ConfigurableApplicationContext context ;
      4. public static void main(String[] args) {
      5. context = SpringApplication.run(FactorybeanDemoApplication.class, args);
      6. TestA testA = (TestA)context.getBean("0");
      7. testA.print();
      8. TestB testB = (TestB)context.getBean("1");
      9. testB.print();
      10. }
      11. }

      3.3  统一 pom

      1. "1.0" encoding="UTF-8"?>
      2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      4. <modelVersion>4.0.0modelVersion>
      5. <groupId>com.factorybeangroupId>
      6. <artifactId>factorybean-demoartifactId>
      7. <version>0.0.1-SNAPSHOTversion>
      8. <packaging>jarpackaging>
      9. <name>factorybean-demoname>
      10. <description>factorybean注入方式 project for Spring Bootdescription>
      11. <parent>
      12. <groupId>org.springframework.bootgroupId>
      13. <artifactId>spring-boot-starter-parentartifactId>
      14. <version>2.1.0.RELEASEversion>
      15. <relativePath/>
      16. parent>
      17. <properties>
      18. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
      19. <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
      20. <java.version>1.8java.version>
      21. properties>
      22. <dependencies>
      23. <dependency>
      24. <groupId>org.springframework.bootgroupId>
      25. <artifactId>spring-boot-starter-webartifactId>
      26. dependency>
      27. <dependency>
      28. <groupId>org.springframework.bootgroupId>
      29. <artifactId>spring-boot-devtoolsartifactId>
      30. <scope>runtimescope>
      31. dependency>
      32. <dependency>
      33. <groupId>org.springframework.bootgroupId>
      34. <artifactId>spring-boot-starter-testartifactId>
      35. <scope>testscope>
      36. dependency>
      37. dependencies>
      38. <build>
      39. <plugins>
      40. <plugin>
      41. <groupId>org.springframework.bootgroupId>
      42. <artifactId>spring-boot-maven-pluginartifactId>
      43. plugin>
      44. plugins>
      45. build>
      46. project>

      4、源码分析

      5、参考文献

      https://zhuanlan.zhihu.com/p/653695574

      https://blog.csdn.net/u014365523/article/details/118683004

      https://blog.csdn.net/f5465245/article/details/123551991

      https://blog.csdn.net/qq_22986265/article/details/112791601

      https://www.cnblogs.com/zhouzhongqing/p/15182101.html

    32. 相关阅读:
      Python之第六章 内置容器 --- 正则表达式
      128.(前端)增加商品前数据处理——将二维数组转成字符串形式传递
      Day20_9 前端入门之CSS样式
      如何在IIS7里设置实现访问.txt文件是下载模式
      C++ 模板泛型编程
      易基因:植物宏病毒组研究:植物病毒的进化与生态 | 顶刊综述
      javaSE I/O流(二)—— 各种各样的流
      javaWeb过滤器Filter(二)
      5G创新突破 | 紫光展锐5G芯片全球首发R17 NR广播端到端业务演示
      [云原生.docker安装]Centos7安装docker环境
    33. 原文地址:https://blog.csdn.net/yh250648050/article/details/133972781