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();
    }

}
相关推荐
shuair19 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存
计算机程序设计小李同学20 小时前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
Charlie_lll21 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode
qq_124987075321 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
VX:Fegn08951 天前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
Chasmれ1 天前
Spring Boot 1.x(基于Spring 4)中使用Java 8实现Token
java·spring boot·spring
汤姆yu1 天前
2026基于springboot的在线招聘系统
java·spring boot·后端
计算机学姐1 天前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
落霞的思绪1 天前
Spring AI Alibaba 集成 Redis 向量数据库实现 RAG 与记忆功能
java·spring·rag·springai
hssfscv1 天前
Javaweb学习笔记——后端实战8 springboot原理
笔记·后端·学习