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



    4.0.0

    com.factorybean
    factorybean-demo
    0.0.1-SNAPSHOT
    jar

    factorybean-demo
    factorybean注入方式 project for Spring Boot

    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.0.RELEASE
         
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



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

你可能感兴趣的:(Spring,spring)