BeanDefinitionRegistryPostProcessor——动态注册Bean到Spring容器

本文探讨了在Spring框架中如何通过自定义BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor来动态注册和修改Bean。详细介绍了BeanDefinitionRegistryPostProcessor的两个关键方法:postProcessBeanDefinitionRegistry和postProcessBeanFactory的作用及其实现过程。

我宁愿靠自己的力量,打开我的前途,而不愿求有力者垂青。——《悲惨世界》

1、理论

一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下:

  1. xml中通过bean节点来配置;
  2. 使用@Service、@Controller、@Conponent等注解。

最近在研究通过Spring初始化时扫描自定义注解,查到了通过实现BeanDefinitionRegistryPostProcessor获取Bean,从而获得自定义注解。

Spring支持我们通过代码来将指定的类注册到spring容器中。

在这里插入图片描述

Spring容器初始化时,从资源中读取到bean的相关定义后,保存在BeanDefinitionMap,在实例化bean的操作就是依据这些bean的定义来做的,而在实例化之前,Spring允许我们通过自定义扩展来改变bean的定义,定义一旦变了,后面的实例也就变了,而beanFactory后置处理器,即BeanFactoryPostProcessor就是用来改变bean定义的。
在这里插入图片描述
通过invokeBeanFactoryPostProcessors方法用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义。

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:

  1. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
    该方法的实现中,主要用来对bean定义做一些改变。

  2. void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
    该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力。

在这里插入图片描述
从BeanDefinitionRegistry可以看到,BeanDefinitionRegistry提供了丰富的方法来操作BeanDefinition,判断、注册、移除等方法都准备好了,我们在编写postProcessBeanDefinitionRegistry方法的内容时,就能直接使用入参registry的这些方法来完成判断和注册、移除等操作。

org.springframework.context.support.AbstractApplicationContext#refresh中的invokeBeanFactoryPostProcessors(beanFactory);用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义。

invokeBeanFactoryPostProcessors(beanFactory)实际上是委托org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());方法处理的。

在这里插入图片描述

首先处理BeanFactoryPostProcessor中的内容:
在这里插入图片描述

所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;

boolean reiterate = true;
while (reiterate) {
    reiterate = false;
    //查出所有实现了BeanDefinitionRegistryPostProcessor接口的bean名称
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        //前面的逻辑中,已经对实现了PriorityOrdered和Ordered的bean都处理过了,因此通过processedBeans过滤,processedBeans中没有的才会在此处理
        if (!processedBeans.contains(ppName)) {
            //根据名称和类型获取bean
            BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中
            registryPostProcessors.add(pp);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean的名称全部放在processedBeans中
            processedBeans.add(ppName);
            //执行此bean的postProcessBeanDefinitionRegistry方法
            pp.postProcessBeanDefinitionRegistry(registry);
            //改变退出while的条件
            reiterate = true;
        }
    }
}
/registryPostProcessors中保存了所有执行过postProcessBeanDefinitionRegistry方法的bean,
//现在再来执行这些bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
//regularPostProcessors中保存的是所有入参中带来的BeanFactoryPostProcessor实现类,并且这里面已经剔除了BeanDefinitionRegistryPostProcessor的实现类,现在要让这些bean执行postProcessBeanFactory方法

2、实战代码

public class AnnotationScannerConfigurer implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
		// 创建一个bean的定义类的对象
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestServiceImpl.class);
		// 将Bean 的定义注册到Spring环境
		beanDefinitionRegistry.registerBeanDefinition("testService", rootBeanDefinition);
	}
	
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
	  // bean的名字为key, bean的实例为value
		Map<String, Object> beanMap = configurableListableBeanFactory.getBeansWithAnnotation(AutoDiscoverClass.class);
		}

其实在实际使用过程中,Spring启动时扫描自定义注解,是通过BeanFactoryPostProcessor接口的postProcessBeanFactory方法,configurableListableBeanFactory.getBeansWithAnnotation(AutoDiscoverClass.class);获取每一个有自定义注解的Bean。这种方法没满足我的实际需求。

总结下,BeanFactoryPostProcessor可以修改各个注册的Bean,BeanDefinitionRegistryPostProcessor可以动态将Bean注册。

1. 熟悉Spring管理Bean生命周期和依赖注入,使用注解进行自动装配。 使用spring.xml文件去声明,将bean将给spring容器管理 Bean的生命周期-五步骤版本 1. 实例化 创建对象 类被加载的时候会调用类的无参构造方法 2. 依赖注入 给属性赋值,调用类的属性的set方法 3. 初始化 初始化方法init需要自己定义,交给spring容器去执行,在spring.xml文件去声明 =======================前三步spring容器会在调用前会自动执行============================= 4. 使用Bean 使用BeanFeactory或者ApplicationContext读取spring.xml配置获取spring容器 使用getBean(*.class)获取bean实例使用bean 5. 销毁Bean 使用close()调用destory方法 销毁方法destory需要自己定义,交给spring容器去执行,在spring.xml文件去声明 Bean的生命周期-七步骤版本 1. 实例化 创建对象 类被加载的时候会调用类的无参构造方法 2. 依赖注入 给属性赋值,调用类的属性的set方法 3. 初始化前,创建后置处理器实现BeanPostProcessor接口的before方法,也交给spring容器管理,拦截目标bean 4. 初始化 初始化方法init需要自己定义,交给spring容器去执行,在spring.xml文件去声明 5. 初始化后,创建后置处理器实现BeanPostProcessor接口的after方法,也交给spring容器管理,拦截目标bean =======================前三步spring容器会在调用前会自动执行============================= 6. 使用Bean 使用BeanFeactory或者ApplicationContext读取spring.xml配置获取spring容器 使用getBean(*.class)获取bean实例使用bean 7. 销毁Bean 使用close()调用destory方法 销毁方法destory需要自己定义,交给spring容器去执行,在spring.xml文件去声明 Bean的生命周期-十步骤版本 1.
05-10
### SpringBean 的生命周期及其各个阶段的详细步骤 Spring 容器管理着 Bean 的整个生命周期,从创建到销毁都由容器负责。以下是关于 SpringBean 生命周期的详细描述: #### 1. **加载配置文件** Spring 容器启动时会读取配置元数据(XML 文件、Java 注解或 Java 配置类),这些元数据包含了如何创建和组装 Bean 的信息。 #### 2. **注册 BeanDefinition** 在此阶段,Spring 将解析所有的 Bean 定义并将其存储在内存中的 `BeanDefinition` 对象中[^1]。这一步骤涉及到了 `BeanDefinitionRegistryPostProcessor` 接口实现类的作用,它允许开发者修改已有的 `BeanDefinition` 或者动态注册新的 `BeanDefinition` 到容器中。 #### 3. **实例化 Bean** 当需要某个具体的 Bean 实例时,Spring 开始执行其构造函数来创建该对象。如果存在多个构造函数,则按照依赖注入的原则选择合适的构造函数进行实例化[^4]。 #### 4. **属性填充 (Population of Properties)** 创建好 Bean 实例后,Spring 根据配置为其设置相应的属性值以及注入其他依赖项。这一过程可能涉及到自动装配 (`@Autowired`) 或者显式的 setter 方法调用来完成依赖关系绑定[^4]。 #### 5. **应用 BeanNameAware, BeanFactoryAware 等 Aware 接口回调方法** 如果当前 Bean 实现了一些特定接口比如 `BeanNameAware`, `BeanClassLoaderAware` 等,在这个时刻就会触发它们对应的回调逻辑以便让 Bean 获得一些上下文环境的信息。 #### 6. **调用 BeanPostProcessor 前处理(preProcessBeforeInitialization)** 这里引入了第一个重要的扩展点——`BeanPostProcessor` 接口。对于每一个即将被初始化前后的 Bean ,都会依次经过所有实现了 `postProcessBeforeInitialization(Object bean, String beanName)` 和 `postProcessAfterInitialization(Object bean, String beanName)` 方法的对象加工改造[^3]。 #### 7. **初始化操作(Invocation Of Initialization Methods And InitializingBean.afterPropertiesSet())** 经过前面几步准备工作之后,现在正式进入初始化环节。这里有三种方式可以指定初始化动作: - 使用标准 Javabean 规范下的 `afterPropertiesSet()` 方法; - 自定义通过 XML 属性或者注解声明的方式指明某方法作为初始话入口; - 加上 JSR-250 提供的标准注解 `@PostConstruct` 来标记希望被执行的一次性设定工作[^2]。 #### 8. **再次调用 BeanPostProcessor 后处理(postProcessAfterInitialization)** 类似于第6步的操作只是顺序颠倒过来而已。此时已经完成了正常的初始化流程,所以这里给予最后一次机会让用户自定义调整最终状态[^3]。 #### 9. **使用阶段** 至此为止,一个完整的可用 Bean 已经准备好接受业务请求服务啦! #### 10. **销毁阶段(Destruction Phase With DisposableBean.destroy() Or Custom Destroy Method)** 应用程序关闭期间,Spring Framework 可以帮助清理资源释放等工作。同样支持多种机制去定义结束期行为: - 实现 `DisposableBean` 接口中唯一的 destroy 函数即可; - 设置专门用于终结工作的 destroyMethod 参数指向相应的方法名; - 添加 `@PreDestroy` 注解至目标成员变量之上表示在其所属组件消亡之前运行一段代码片段[^4]. --- ```java @Component public class MyBean implements InitializingBean, DisposableBean { private static final Logger logger = LoggerFactory.getLogger(MyBean.class); public MyBean(){ System.out.println("MyBean Constructor Called"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("@Override InitializingBean.afterPropertiesSet()"); } @PostConstruct public void postConstructInit(){ System.out.println("@PostConstruct Init method called."); } @Override public void destroy() throws Exception { System.out.println("DisposableBean.destroy() invoked!"); } @PreDestroy public void preDestroyCleanup(){ System.out.println("@PreDestroy Cleanup logic executed."); } } ``` ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值