• Spring扩展接口(2):BeanDefinitionRegistryPostProcessor


    在此系列文章中,我总结了Spring几乎所有的扩展接口,以及各个扩展点的使用场景。并整理出一个bean在spring中从被加载到最终初始化的所有可扩展点的顺序调用图。这样,我们也可以看到bean是如何一步步加载到spring容器中的。


    BeanDefinitionRegistryPostProcessor

    1、概述

    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
        void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
    }
    

    BeanDefinitionRegistryPostProcessor为容器级后置处理器。容器级的后置处理器会在Spring容器初始化后、刷新前执行一次。还有一类为Bean级后置处理器,在每一个Bean实例化前后都会执行。

    通常,BeanDefinitionRegistryPostProcessor用于在bean解析后实例化之前通过BeanDefinitionRegistry对BeanDefintion进行增删改查。

    常见如mybatis的Mapper接口注入就是实现的此接口。

    2、简单案例

    下面是一个示例,展示了如何实现动态的给spring容器添加一个Bean:

    public class User {
        String name;
        String password;
    }
    
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.MutablePropertyValues;
    import org.springframework.beans.PropertyValue;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.core.Ordered;
    import org.springframework.stereotype.Component;
    
    @Component
    public class DynamicBeanRegistration implements BeanDefinitionRegistryPostProcessor, Ordered {
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClass(User.class);
            MutablePropertyValues propertyValues = new MutablePropertyValues();
            PropertyValue propertyValue1 = new PropertyValue("name", "张三");
            PropertyValue propertyValue2 = new PropertyValue("password", "123456");
            propertyValues.addPropertyValue(propertyValue1);
            propertyValues.addPropertyValue(propertyValue2);
            beanDefinition.setPropertyValues(propertyValues);
            beanRegistry.registerBeanDefinition("user", beanDefinition);
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
            System.out.println(beanDefinition.getBeanClassName());
            User user = beanFactory.getBean(User.class);
            System.out.println(user.getName());
            System.out.println(user.getPassword());
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    
    

    输出:

    com.sandy.springex.beanfefinitionregistrypostprocessor.User
    张三
    123456
    
    • 首先定义了一个名为"User"的Java类,包含了两个属性:name和password。
    • 然后定义了一个名为"DynamicBeanRegistration"的组件(通过@Component注解),实现了BeanDefinitionRegistryPostProcessor接口和Ordered接口。
    • 在postProcessBeanDefinitionRegistry方法中,创建了一个RootBeanDefinition对象,并设置其beanClass为User类。接着创建了一个MutablePropertyValues对象,并通过PropertyValue对象设置了name和password属性的值。最后,将propertyValues设置到beanDefinition中,并使用beanRegistry注册了一个名为"user"的BeanDefinition。
    • 在postProcessBeanFactory方法中,通过beanFactory获取了名为"user"的BeanDefinition,并输出了其beanClassName。然后使用beanFactory获取了一个User对象,并输出了其name和password属性的值。

    该代码通过实现BeanDefinitionRegistryPostProcessor接口,在Spring容器启动时动态注册了一个名为"user"的Bean,并设置了其name和password属性的值。在后续的BeanFactory初始化过程中,可以通过beanFactory获取到该动态注册的Bean,并访问其属性值。

    当容器中有多个BeanDefinitionRegistryPostProcessor的时候,可以通过实现Ordered接口来指定顺序:

    @Override
    public int getOrder() {
       return 0; //值越小,优先级越高
    }
    

    3、源码分析

    • 在DynamicBeanRegistration打上断点,启动SpringApplication,可以看到左下角的调用链路。

    • 红框中5步都是在springboot中进行,最后super.refresh()是调用大家熟悉的spring的AbstractApplicationContext的refresh方法。

    • 继续向下看


    • 接下来进入核心的invokeBeanFactoryPostProcessors方法,大概逻辑是先取出所有实现了BeanDefinitionRegistryPostProcessor接口的类,然后优先调用实现了PriorityOrdered接口的组件,再调用实现了Ordered接口的组件。

    • 最后,遍历调用BeanDefinitionRegistryPostProcessor组件postProcessBeanDefinitionRegistry方法

    我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=31qu12pkd8qo8

  • 相关阅读:
    深信服测开实习
    vue学习笔记,购物车清单制作
    C- strtok() & strtok_r()
    macOS下VS Code 使用记录(使用调试运行 Python/C 等)
    篇7:Ubuntu18.04 ifconfig时没有虚拟网卡了
    接雨水-热题 100?-Lua 中文代码解题第4题
    AVL的单旋和双旋—附图超详细
    微软如何打造数字零售力航母系列科普12 - 使用Microsoft Fabric将客户数据带入人工智能时代
    每日一题:探究响应式本质,以最简单的方式理解响应式
    一个十分好用且美观的vue3后台管理系统框架
  • 原文地址:https://www.cnblogs.com/myshare/p/17754010.html