Spring Bean初始化与拓展点梳理

概述

拓展接口 作用
BeanFactoryPostProcessor 此接口提供了一个机会,在bean实例化之前修改bean的定义,PropertyPlaceholderConfigurer,就是在这个扩展点上对 Bean 属性中的占位符进行替换。
BeanDefinitionRegistryPostProcessor 它扩展自BeanFactoryPostProcessor,在执行 BeanFactoryPostProcessor 的功能前,提供了可以添加 Bean Definition 的能力,允许在初始化一般 Bean 前,注册额外的 Bean,spring注解实现类ConfigurationClassPostProcessor就是继承了这个接口
BeanPostProcessor 提供了在 Bean 初始化之前和之后插入自定义逻辑的能力。与 BeanFactoryPostProcessor 的区别是处理的对象不同,BeanFactoryPostProcessor 是对 BeanFactory 进行处理,BeanPostProcessor 是对 Bean 进行处理,Spring AOP就是依赖该接口实现的
InitializingBean 可以在 Bean 初始化完成,所有属性设置完成后执行特定逻辑,例如对自动装配对属性进行验证等。
DisposableBean 用于在 Bean 被销毁前执行特定的逻辑,例如做一些回收工作等。ApplicationListener,用来监听 Spring 的标准应用事件或者自定义事件。

PS:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、BeanPostProcessor可以通过实现 Ordered 和PriorityOrdered 接口来指定执行顺序。实现 PriorityOrdered 接口的 processor 会先于实现 Ordered 接口的执行。

BeanFactoryPostProcessor

主要功能

  1. 修改Bean定义
    • 在Spring加载所有bean定义后,但在它开始实例化这些bean之前,BeanFactoryPostProcessor会被调用。这意味着我们可以使用它来修改这些bean定义。
  2. 更改属性值
    • 我们可以更改bean的属性或依赖,这在某些场景下,如需要根据环境或其他外部因素动态地配置bean时,会非常有用。
  3. 添加或删除Bean定义
    • 不仅可以修改现有的bean定义,还可以添加新的bean定义或删除现有的bean定义。
  4. 应用多个BeanFactoryPostProcessors
    • 如果有多个BeanFactoryPostProcessor,我们可以通过实现Ordered接口来控制它们的执行顺序。

Demo

java 复制代码
public class BeanFactoryPostProcessorApplication {

    public static class TestBean {
        public void show() {
            System.out.println("instance: " + this);
        }
    }

    public static class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("修改bean的定义");
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition("beanFactoryPostProcessorApplication.TestBean");
            beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            System.out.println("将mySimpleBean从默认的单例修改成多例");
            System.out.println("修改bean的定义已完成");
        }
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                TestBean.class,
                MyBeanFactoryPostProcessor.class
        );
        TestBean mySimpleBean1 = context.getBean(TestBean.class);
        TestBean mySimpleBean2 = context.getBean(TestBean.class);

        mySimpleBean1.show();
        mySimpleBean2.show();
    }

}

BeanDefinitionRegistryPostProcessor

主要功能

  1. 注册新的 Bean 定义
    • 该接口提供了一个机制,允许在 Spring 容器完成其标准初始化(即加载所有 bean 定义)之后,但在任何 bean 实例化之前,动态注册新的 bean 定义。
  2. 修改现有的 Bean 定义
    • 除了能够添加新的 bean 定义,BeanDefinitionRegistryPostProcessor 还可以修改已经注册的 bean 定义。例如,它可以修改 bean 的属性值、构造函数参数或其它设置。
  3. 控制 BeanFactoryPostProcessor 的执行顺序
    • 因为 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 的子接口,它的实现还可以控制 BeanFactoryPostProcessor 的执行顺序。这是因为在 Spring 容器启动时,所有的 BeanDefinitionRegistryPostProcessor beans 首先会被实例化和调用,然后才是其他的 BeanFactoryPostProcessor beans。
  4. 基于条件的 Bean 注册
    • 可以利用 BeanDefinitionRegistryPostProcessor 来基于特定的运行时条件(例如类路径上是否存在某个特定的类)来决定是否注册某个 bean。
  5. 扩展点以实现高级配置
    • 对于复杂的应用或框架,这个接口提供了一个扩展点,可以在初始化过程中进行更高级的配置,如加载外部的配置或执行特殊的验证逻辑。

Demo

java 复制代码
public class BeanFactoryPostProcessorApplication {

    public static class TestBean {
        public void show() {
            System.out.println("instance: " + this);
        }
    }

    public static class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("修改bean的定义");
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition("beanFactoryPostProcessorApplication.TestBean");
            beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            System.out.println("将mySimpleBean从默认的单例修改成多例");
            System.out.println("修改bean的定义已完成");
        }

        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            System.out.println("开始新增Bean定义");
            // 创建一个新的 BeanDefinition 对象
            BeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
            // 使用 registry 来注册这个新的 bean 定义
            registry.registerBeanDefinition("beanFactoryPostProcessorApplication.TestBean", beanDefinition);
            System.out.println("完成新增Bean定义");
        }
    }



    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                MyBeanFactoryPostProcessor.class
        );
        TestBean mySimpleBean1 = context.getBean(TestBean.class);
        TestBean mySimpleBean2 = context.getBean(TestBean.class);

        mySimpleBean1.show();
        mySimpleBean2.show();
    }

}

BeanPostProcessor与InitializingBean

BeanPostProcessor主要功能

修改 Bean 属性:在 Bean 初始化之前或之后,可以修改 Bean 的属性。例如,可以根据某些条件为 Bean 的某些属性设置默认值。

验证 Bean 的状态:在 Bean 初始化完成后,可以检查 Bean 的状态,确保它满足某些条件或约束。

返回代理 Bean:最常见的用例是返回一个代理(proxy)来包装原始的 Bean。例如,Spring AOP 使用它来为目标 Bean 创建代理,从而实现切面的功能。

改变返回的 Bean 类型:可以完全替换一个 Bean 的实例,返回一个不同类型的对象。这是一个高级用例,但在某些场景中可能是必要的

InitializingBean主要功能

  1. 初始化回调

    • InitializingBean 接口为 Spring 容器提供了一个机制,以确保在 bean 的所有属性都被设置后,但在 bean 被其他组件使用之前,可以执行某些初始化逻辑或操作。
  2. 属性验证

    • afterPropertiesSet 方法中,我们可以验证 bean 的属性是否都已正确设置,特别是一些必要的属性。
  3. 自定义初始化逻辑

    • 如果 bean 需要进行特定的初始化操作,如开启资源、连接数据库、启动某些线程或其他任何初始化活动,那么这些操作可以在 afterPropertiesSet 方法中进行。
  4. 生命周期管理

    • InitializingBean 是 Spring 生命周期中的一个关键点,它在属性注入 (Property Injection) 之后和使用 bean 之前被调用。这提供了一个干净的生命周期钩子,可以用来确保 bean 在被使用之前是完全准备好的。

PS:尽管 InitializingBean 提供了一个初始化 bean 的方式,但现代的 Spring 我们更倾向于使用 @PostConstruct 注解,因为它是 JSR-250 的一部分,不依赖于 Spring 特定的接口。

Demo

java 复制代码
public class BeanFactoryPostProcessorApplication {

    public static class TestBean implements InitializingBean {
        public TestBean() {
            System.out.println("1. TestBean 构造函数");
        }

        public void show() {
            System.out.println("instance: " + this);
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("3. afterPropertiesSet");
        }
    }

    public static class MyBeanFactoryPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("2. postProcessBeforeInitialization");
            return bean;
        }


        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("4. postProcessAfterInitialization");
            return bean;
        }
    }


    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                MyBeanFactoryPostProcessor.class,
                TestBean.class
        );
        TestBean mySimpleBean1 = context.getBean(TestBean.class);
        mySimpleBean1.show();
    }

}

DisposableBean

主要功能

  1. 销毁回调
    • 当 bean 被 Spring 容器销毁时,如果它实现了 DisposableBean 接口,容器会自动调用其 destroy() 方法。这为 beans 提供了一个机会在销毁之前执行任何必要的清理操作。

Demo

java 复制代码
public class BeanFactoryPostProcessorApplication {

    public static class TestBean implements DisposableBean {
        @Override
        public void destroy() {
            System.out.println("destroy");
        }
    }


    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                TestBean.class
        );
        context.close();
    }

}
相关推荐
2401_857636394 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
2401_857610034 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端
代码小鑫5 小时前
A027-基于Spring Boot的农事管理系统
java·开发语言·数据库·spring boot·后端·毕业设计
海波东5 小时前
某m大厂面经1
java·spring
颜淡慕潇6 小时前
【K8S问题系列 | 9】如何监控集群CPU使用率并设置告警?
后端·云原生·容器·kubernetes·问题解决
荆州克莱6 小时前
Mysql学习笔记(一):Mysql的架构
spring boot·spring·spring cloud·css3·技术
独泪了无痕6 小时前
WebStorm 如何调试 Vue 项目
后端·webstorm
怒放吧德德7 小时前
JUC从实战到源码:JMM总得认识一下吧
java·jvm·后端
代码小鑫8 小时前
A025-基于SpringBoot的售楼管理系统的设计与实现
java·开发语言·spring boot·后端·毕业设计