• Spring注解驱动之BeanDefinitionRegistryPostProcessor原理


    概述

    BeanDefinitionRegistryPostProcessor概述

    在这里插入图片描述
    可以看到BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口。
    注释中说执行时机是所有合法的bean定义已经加载,但是还没实例化。
    看起来和BeanFactoryPostProcessor执行时机差不多,但是BeanFactoryPostProcessor的注释是所有bean定义被加载,而BeanDefinitionRegistryPostProcessor是所有合法的bean定义。
    接着看注释:

    This allows for adding further bean definitions before the next post-processing phase kicks in.
    
    • 1

    意思是BeanDefinitionRegistryPostProcessor允许添加将来的bean定义在下一个后置处理器阶段开始之前。简单说就是还可以往容器中增加新的bean的定义。
    因此,大概率BeanDefinitionRegistryPostProcessor的执行顺序在BeanFactoryPostProcessor之前。

    案例实践

    首先,编写一个类,例如MyBeanDefinitionRegistryPostProcessor,它应要实现BeanDefinitionRegistryPostProcessor这个接口。

    package com.meimeixia.ext;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.AbstractBeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.stereotype.Component;
    
    import com.meimeixia.bean.Blue;
    
    // 记住,我们这个组件写完之后,一定别忘了给它加在容器中
    @Component
    public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
    	@Override
    	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:" + beanFactory.getBeanDefinitionCount());
    	}
    
    	/**
    	 * 这个BeanDefinitionRegistry就是Bean定义信息的保存中心,这个注册中心里面存储了所有的bean定义信息,
    	 * 以后,BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息来创建bean实例的。
    	 * 
    	 * bean定义信息包括有哪些呢?有这些,这个bean是单例的还是多例的、bean的类型是什么以及bean的id是什么。
    	 * 也就是说,这些信息都是存在BeanDefinitionRegistry里面的。
    	 */
    	@Override
    	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("postProcessBeanDefinitionRegistry...bean的数量:" + registry.getBeanDefinitionCount());
    		// 除了查看bean的数量之外,我们还可以给容器里面注册一些bean,我们以前也简单地用过
    		/*
    		 * 第一个参数:我们将要给容器中注册的bean的名字
    		 * 第二个参数:BeanDefinition对象
    		 */
    		// RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class); // 现在我准备给容器中添加一个Blue对象
    		// 咱们也可以用另外一种办法,即使用BeanDefinitionBuilder这个构建器生成一个BeanDefinition对象,很显然,这两种方法的效果都是一样的
    		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
    		registry.registerBeanDefinition("hello", beanDefinition);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    测试结果
    在这里插入图片描述
    可以看到,BeanDefinitionRegistryPostProcessor里面的两个方法,postProcessBeanDefinitionRegistry在postProcessBeanFactory之前执行。
    BeanDefinitionRegistryPostProcessor比BeanFactoryPostProcessor先执行。

    源码分析

    自己在测试示例中方法打断点,然后查看调用栈即可,下面是一些主要的代码片段。
    在这里插入图片描述
    在这里插入图片描述
    继续向下看,可以看到会取出所有实现了BeanDefinitionRegistryPostProcessor接口的类,即从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。然后,优先调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor组件。
    在这里插入图片描述
    在这里插入图片描述
    点进去这个方法里面一看究竟,原来是先调用完BeanDefinitionRegistryPostProcessor组件里面的postProcessBeanDefinitionRegistry方法,然后再来调用它里面的postProcessBeanFactory方法。
    我们再来仔细看一下PostProcessorRegistrationDelegate类中的invokeBeanFactoryPostProcessors方法,只不过这时是从程序停留的地方(即第122行代码处)往下看,如下图所示。
    在这里插入图片描述

    小结

    BeanDefinitionRegistryPostProcessor的执行流程。

    1. 创建IOC容器。
    2. 调用refresh方法。
    3. 从IOC容器中获取所有的BeanDefinitionRegistryPostProcessor组件,并依次触发它们的postProcessBeanDefinitionRegistry方法,之后触发它的postProcessBeanFactory方法。
    4. 从IOC容器中获取到所有的BeanFactoryPostProcessor组件,并依次触发它们的postProcessBeanFactory方法。

    参考

    Spring注解驱动开发第37讲——你知道Spring中BeanDefinitionRegistryPostProcessor是如何执行的吗?

  • 相关阅读:
    Elasticsearch:Dynamic templates
    chatgpt赋能python:Python阶乘算法——快速、高效的算法实现!
    wsl使用vscode连接,远程安装C/C++ 拓展时,报错
    java划分每个月的周数及其每周的开始时间和结束时间
    微信小程序实现腾讯地图
    电机的基础知识
    Vue状态管理 Storage Vuex Pinia
    Python环境搭建(Python、 Pycharm安装/pycharm创建python虚拟环境Virtualenv)基础
    14.11 Socket 基于时间加密通信
    [附源码]计算机毕业设计校园快递柜存取件系统Springboot程序
  • 原文地址:https://blog.csdn.net/tianzhonghaoqing/article/details/126918816