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)

public class MyBean {
    private String message = "Hello, World!";

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

3.1.2  手写一个接口

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

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    /**
     * 重写BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // 创建一个RootBeanDefinition实例,该实例对应的BeanClass是MyBean
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
        // 向BeanDefinitionRegistry注册MyBean的BeanDefinition
        registry.registerBeanDefinition("myBean", beanDefinition);

        // 查询和修改
        BeanDefinition myBean = registry.getBeanDefinition("myBean");
        System.out.println(myBean);
        // 删除
        registry.removeBeanDefinition("myBean");

    }

    /**
     * 重写BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    @Override
    public int getOrder() {
        return 1;
    }
}

3.1.3  启动类

@SpringBootApplication
public class FactorybeanDemoApplication {

    public static ConfigurableApplicationContext context ;

    public static void main(String[] args) {
        context = SpringApplication.run(FactorybeanDemoApplication.class, args);
        MyBean bean = context.getBean(MyBean.class);
        System.out.println("================"+bean.getMessage()+"===================");
    }
}
  • 上述代码会抛出No qualifying bean异常,因为我们把myBean的bd删除了
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.factorybean.factorybeandemo.factorybean.test.MyBean' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:343)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)
	at com.factorybean.factorybeandemo.FactorybeanDemoApplication.main(FactorybeanDemoApplication.java:17)
	... 5 more
  • 注释掉“registry.removeBeanDefinition("myBean");” 就可以执行成功
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)
================Hello, World!===================

3.2  案例二

3.2.1   配置类 (MyPostBeanRegistar)

@Configuration
public class MyPostBeanRegistar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

        System.out.println("postProcessBeanDefinitionRegistry is invoked");

        String clzz= Base.class.getName();


        for(int i=0;i<2;i++){
            if(!beanDefinitionRegistry.containsBeanDefinition(i+""))
                ResgistarUtils.registerBeanDefinations(i+"",clzz,beanDefinitionRegistry);
        }

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("postProcessBeanFactory is invoked");
    }
}

3.2.2  注册Utils类 (ResgistarUtils)

public class ResgistarUtils {

    /**
     * 注册工具类方法
     * @param className
     * @param clzz
     * @param beanDefinitionRegistry
     */
    public static void  registerBeanDefinations(String className, String clzz, BeanDefinitionRegistry beanDefinitionRegistry){


        /**
         * 通过 工厂方法来注入Bean
         */
        BeanDefinitionBuilder builder= BeanDefinitionBuilder.genericBeanDefinition(MyfactoryBean.class);

        builder.addPropertyValue("type",clzz);
        builder.addPropertyValue("name",className);
        builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        if(className.equals("0")) {
            beanDefinition.setPrimary(true);
        }else{
            //beanDefinition.s
        }

        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className);
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, beanDefinitionRegistry);
    }
}

3.2.3   工厂bean接口实现

public class MyfactoryBean implements FactoryBean<Object> {
    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private Class<?> type;
    private String name;

    @Override
    public Object getObject() throws Exception {
        System.out.println("getObject");
        if(this.name.equals("0")){
            return new TestA();
        }else if(this.name.equals("1")){
            return new TestB();

        }
       throw new ClassNotFoundException("not found Base by name=["+name+"]");
    }

    @Override
    public Class<?> getObjectType() {
        return type;
    }

}

3.2.4  Entity 类 (Base、TestA、TestB)

public interface Base {
    void print();
}
public class TestA implements Base {

    public TestA(){
        System.out.println("TestA 够着");
    }
    @Override
    public void print() {
        System.out.println("testA aaa");
    }
}
public class TestB implements Base {

    public TestB(){
        System.out.println("TestB 够着");
    }

    @Override
    public void print() {
        System.out.println("testB bbbb ");
    }
}

3.2.5  测试 Controller 类 (TestController)

@RestController
public class TestController {

    @Autowired
    Base base1;

//    @Autowired
//    @Qualifier("1")
    @Resource(name = "1")
    Base base2;

    @GetMapping("/testprint")
    public String print(){
        base1.print();
        base2.print();
        return "testprint";
    }
}

3.2.6  启动类

@SpringBootApplication
public class FactorybeanDemoApplication {

    public static ConfigurableApplicationContext context ;

    public static void main(String[] args) {
        context = SpringApplication.run(FactorybeanDemoApplication.class, args);
        TestA testA = (TestA)context.getBean("0");
        testA.print();
        TestB testB = (TestB)context.getBean("1");
        testB.print();
    }
}

3.3  统一 pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.factorybean</groupId>
    <artifactId>factorybean-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>factorybean-demo</name>
    <description>factorybean注入方式 project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Gateway是一个基于Spring Cloud的微服务网关,用于构建高效、可靠的微服务架构。它提供了一种简单而强大的方式来路由、过滤和转换请求,帮助开发者构建弹性、可扩展的微服务应用。 Spring Cloud Gateway的功能和工作原理可以通过以下几点来详解: 1. 网关功能:Spring Cloud Gateway作为一个API网关,具有路由、过滤和转发请求的功能。它可以根据请求的URL、请求头、请求参数等信息,将请求转发到不同的微服务实例上。 2. 网关路由:Spring Cloud Gateway支持基于路由规则的请求转发。开发者可以通过配置路由规则,将特定的请求路径映射到相应的微服务实例上。这样可以实现负载均衡、服务发现等功能。 3. 网关过滤:Spring Cloud Gateway支持请求过滤器,可以在请求到达网关之前或之后对请求进行一系列操作。开发者可以根据需要添加自定义的过滤器,实现请求认证、请求转换、请求限流等功能。 4. 响应式框架:Spring Cloud Gateway基于Spring WebFlux框架,采用异步非阻塞的方式处理请求。这使得网关在高并发场景下具备更好的性能和吞吐量。 总之,Spring Cloud Gateway是一个功能强大的微服务网关,可以作为微服务架构的入口,实现请求的路由、过滤和转发。它采用响应式框架来处理请求,具备高并发和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【SpringCloud】SpringCloud原理之Gateway网关](https://blog.csdn.net/twotwo22222/article/details/129428040)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringCloud Gateway 详解](https://blog.csdn.net/m0_51111980/article/details/128022758)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值