Spring 之 BeanDefinitionRegistryPostProcessor

Spring 之 BeanDefinitionRegistryPostProcessor

 

 

1、简介

在Spring IoC容器实例化Beans之前,BeanFactoryPostProcessor有权利修改这些beans的配置。在Spring中,所有的beans在被完全实例化之前都是以BeanDefinition的形式存在的。BeanFactoryPostProcessor为我们提供了一个机会,使我们能够在bean完全实例化之前调整和修改这些BeanDefinition。BeanDefinitionRegistryPostProcessor 是Spring中的一个高级扩展接口,继承自 BeanFactoryPostProcessor。它提供了更为深入的方式来干预bean定义的注册过程。能向注册中心 BeanDefinitionRegistry 中动态地添加、修改或移除bean定义。BeanDefinitionRegistryPostProcessor 提供了一个核心方法:postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)。通过该方法,我们可以直接操作 BeanDefinitionRegistry,这是一个专门用于bean定义注册的中心接口。它允许我们直接注册新的bean定义、修改已有的bean定义或者完全移除某些bean定义。

 

2、类关系图

接口定义如下:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean definition registry after its
     * standard initialization. All regular bean definitions will have been loaded,
     * but no beans will have been instantiated yet. This allows for adding further
     * bean definitions before the next post-processing phase kicks in.
     * @param registry the bean definition registry used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

 

关于 BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {
    //注册beanDefinition
   void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
         throws BeanDefinitionStoreException;
    //移除指定的beanDefinition
   void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //根据beanName查询beanDefinition
   BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //判断某个beanDefinition是否已经注册
   boolean containsBeanDefinition(String beanName);
    //获取所有已注册的beanDefinition
   String[] getBeanDefinitionNames();
    //获取所有已注册的beanDefinition的数量
   int getBeanDefinitionCount();
    //判断某个beanDefinition是否已经被使用
   boolean isBeanNameInUse(String beanName);
}

 

3、使用示例:

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

/**
 * @Author
 * @ClassName BeanDefinitionRegistryPostProcessorTest
 * @Description bean 动态修改Bean后置处理器
 * @Date 2023/12/4 23:03
 * @Version 1.0
 */
@Component
public class BeanDefinitionRegistryPostProcessorTest implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 新增Bean
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Student.class);
        registry.registerBeanDefinition("student", beanDefinitionBuilder.getBeanDefinition());
        // 查询和修改
        BeanDefinition studentBeanDefinition = registry.getBeanDefinition("student");
        MutablePropertyValues propertyValues = studentBeanDefinition.getPropertyValues();
        propertyValues.add("name", "张三").add("age", 32);
        // 删除
        registry.removeBeanDefinition("student");
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("============= BeanDefinitionRegistryPostProcessorTest invoke beanFactory =========");
    }
}

 

4、源码解析

4.1、初始化和执行时机

  1. 加载配置: Spring从各种来源(如XML文件、Java配置、注解)加载配置信息。
  2. 解析配置: 根据加载的配置,Spring创建对应的BeanDefinition。
  3. 注册BeanDefinition: 解析完成后,Spring将这些BeanDefinition对象注册到BeanDefinitionRegistry中。
  4. 执行BeanDefinitionRegistryPostProcessor: 这个后置处理器提供了一个重要的扩展点,允许在所有BeanDefinition注册完毕后,但在Bean实例化之前进行一些操作。例如:注册新的BeanDefinition、修改或删除现有的BeanDefinition。
  5. 执行BeanFactoryPostProcessor: 这个后置处理器提供了另一个扩展点,它主要允许查看或修改已经注册的BeanDefinition。例如,根据某些条件更改Bean的作用域或属性值。
  6. 实例化Bean: 这是将BeanDefinition转换为实际的Bean实例的过程。
  7. 依赖注入: 在这一步,Spring 框架会按照 BeanDefinition 的描述为 bean 实例注入所需的依赖。
  8. Bean初始化: 在所有依赖都注入后,特定的初始化方法(如通过@PostConstruct指定的)将会被调用,完成Bean的最后设置。
  9. 执行BeanPostProcessor的方法: BeanPostProcessor提供了拦截的能力,允许在Bean初始化阶段结束之前和之后进行操作。
  10. Bean完全初始化: 在此阶段,Bean 完全初始化并准备好被应用程序使用。

 

4.2、 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 与 BeanPostProcessor  的对比

  • BeanDefinitionRegistryPostProcessor:在所有 BeanDefinition 被加载和注册之后,但 优先于 BeanFactoryPostProcessor 执行主要用于向 BeanDefinitionRegistry 动态注册新的 bean 定义、修改或移除已有的 bean 定义。
  • BeanFactoryPostProcessor :  BeanDefinitionRegistryPostProcessor 类似,但执行的时机不同,BeanFactoryPostProcessor后执行。修改已加载到容器中的 bean 定义的属性,例如更改某个 bean 的作用域、属性值等。
  • BeanPostProcessor  : 针对已经实例化但未完全初始化的 bean对象。 具体是在bean生命周期的初始化方法前后执行。主要用于在bean初始化前后进 行操作,如修改bean属性、生成代理对象等。

 

4.3、在SpringBoot 中的初始化和执行时机

1、 SpringApplication#run方法后,刚开始是一些Spring容器初始化的配置操作,直到执行到org.springframework.boot.SpringApplication#refreshContext,开始容器刷新,进入了关键阶段。

2、 在SpringApplication#refreshContext,实际的刷新逻辑是在org.springframework.context.support.AbstractApplicationContext#refresh方法中;

3、 AbstractApplicationContext#refresh方法中,调用org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors开始初始化和执行实现BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry()和postProcessBeanFactory();

4、 进入AbstractApplicationContext#invokeBeanFactoryPostProcessors方法,发现又调用了org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors();

5、 在PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法中,并不是直接就初始化和执行postProcessBeanDefinitionRegistry()和postProcessBeanFactory(),而是又进行了一系列的判断,其判断顺序是:1、通过AbstractApplicationContext#addBeanFactoryPostProcessor提前注册的BeanDefinitionRegistryPostProcessor实现类;2、实现了PriorityOrdered接口;3、是否实现了Ordered;4、剩下的其他BeanDefinitionRegistryPostProcessor实现类;自定义的BeanDefinitionRegistryPostProcessorTest就属于第4类,所以是所有实现里较晚才被执行的,如果想要提前被执行,可以考虑前面三种方式;

在PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法中执行完BeanDefinitionRegistryPostProcessorTest#postProcessBeanDefinitionRegistry方法后,紧接着就开始执行BeanDefinitionRegistryPostProcessorTest#postProcessBeanFactory方法了;从整个调用过程看postProcessBeanDefinitionRegistry()是早于postProcessBeanFactory()方法执行;

 

posted @ 2022-04-21 13:09  邓维-java  阅读(1104)  评论(0)    收藏  举报