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