Spring 容器生命周期:10大核心扩展接口+实战代码

本文专注讲解 Spring 容器全生命周期的扩展接口、执行顺序、核心作用、实战用法,重点补充每个接口的可运行代码,清晰演示"能拿到什么资源、怎么用",贴合真实开发场景,从入门到精通,一篇就够!

前言

在 Spring 开发中,我们很少直接手写底层扩展接口,但 Spring Boot 自动配置、MyBatis 整合、Nacos 配置中心、AOP、事务等核心功能,底层全靠 Spring 容器生命周期扩展接口实现

作为开发者,掌握这些接口:

  • ✅ 能看懂框架底层源码(比如 MyBatis 如何扫描 Mapper、Nacos 如何注入配置)
  • ✅ 能实现自定义组件、动态配置(比如自定义 Starter、动态注册 Bean)
  • ✅ 能解决启动加载、Bean 初始化、AOP 增强等实际问题
  • ✅ 面试高频必问(Spring 生命周期+扩展点,几乎是中高级后端必考题)

本文整理 Spring 容器最核心的 10 大扩展接口 ,按执行先后顺序 排列,每个接口都包含:执行时机、核心作用、能拿到什么资源、实战代码示例、真实使用场景、触发执行方式,保姆级教程,新手也能直接复制运行,老手可直接用于实战。

一、Spring 容器生命周期总览(极简版)

先记住整体流程,后面逐个接口详解(每个接口对应流程中的一个节点):

启动引导 → 环境准备 → 上下文初始化 → 工厂后置处理 → Bean 定义加载 → Bean 实例化 → Bean 初始化 → AOP 增强 → 容器就绪 → 容器销毁

所有扩展接口严格按顺序执行,这是 Spring 最核心的规则,也是理解扩展点的关键。

二、10大核心扩展接口(按执行顺序,含实战代码+触发方式)

重点说明:所有代码均基于 Spring Boot 2.7.x(最常用稳定版本),可直接复制到项目中运行,每个代码示例都标注"能拿到什么""实战用途",贴合真实开发;同时补充触发执行方式,明确"实现接口后如何让 Spring 调用它"。

1. ApplicationContextInitializer(最早执行)

核心定位:容器刷新前的环境/上下文定制,Spring 最早的扩展点

执行时机 :在 ConfigurableApplicationContext 实例创建完成后,但在调用 context.refresh() 刷新容器之前,此时上下文还未初始化,Bean 定义还未加载。

能拿到什么:ConfigurableApplicationContext(可配置上下文)、Environment(环境对象),能操作环境配置、上下文参数

实战场景:启动时加载配置中心(如 Nacos)配置、激活指定环境(dev/prod)、添加自定义配置源

多重注册的处理: 如果通过多种方式注册了同一个 initializer,或者注册了多个 initializer,它们会按照注册的顺序依次执行。

  • Spring Boot 内部会将通过 spring.factories、配置文件和 API 方式注册的 initializer 合并到一个列表中。
  • 通常顺序是:spring.factories (自动加载) -> 配置文件 (context.initializer.classes) -> API (addInitializers)。后注册的通常排在列表后面,但具体合并逻辑视 Spring Boot 版本实现而定,建议避免重复注册。

实战代码(可直接运行)

java 复制代码
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;

/**
 * 实战用途:启动时加载自定义配置、激活环境,模拟配置中心拉取配置
 */
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 1. 拿到环境对象(核心资源),激活 dev 环境
        ConfigurableEnvironment environment = context.getEnvironment();
        environment.setActiveProfiles("dev"); // 激活 dev 环境,对应 application-dev.yml
        
        // 2. 拿到上下文,设置上下文ID(可用于日志、监控)
        context.setId("my-spring-container");
        System.out.println("上下文ID:" + context.getId());
        
        // 3. 添加自定义配置源(模拟从配置中心拉取的配置)
        Map<String, Object&gt; configMap = new HashMap<>();
        configMap.put("app.name", "spring-lifecycle-demo");
        configMap.put("app.version", "1.0.0");
        // 将自定义配置源添加到最前面,优先级最高(覆盖配置文件中的同名配置)
        environment.getPropertySources().addFirst(new MapPropertySource("customConfig", configMap));
        
        // 4. 验证配置是否生效(拿到配置值)
        String appName = environment.getProperty("app.name");
        System.out.println("从自定义配置源拿到app.name:" + appName);
    }
}

代码说明:通过该接口,能在容器启动最早期拿到环境和上下文,提前配置环境、注入配置,这是 Nacos、Apollo 等配置中心的核心实现方式之一。

触发执行方式:需要手动注册,共4种方式,2种常用方式(二选一即可):

1. 通过 spring.factories 文件自动加载(最常用/推荐)

这是开发 Spring Boot Starter 或希望 initializer 对所有应用自动生效时的标准方式。Spring Boot 启动时会自动扫描类路径下的配置文件并实例化其中定义的 initializer。

  • 配置位置src/main/resources/META-INF/spring.factories

    • 注意:在 Spring Boot 3.x 及 Spring Framework 6+ 中,推荐使用新的文件路径 src/main/resources/META-INF/spring/org.springframework.context.ApplicationContextInitializer.imports,内容为全限定类名列表。旧版的 spring.factories 依然兼容但逐渐被弃用。
  • 配置内容 (spring.factories)

    properties 复制代码
    org.springframework.context.ApplicationContextInitializer=\
    com.example.CustomApplicationContextInitializer
  • 配置内容 (Spring Boot 3+ .imports)

    text 复制代码
    com.example.CustomApplicationContextInitializer
  • 触发时机SpringApplication 构造过程中,通过 SpringFactoriesLoader 自动加载。

2. 通过 application.properties / application.yml 配置

如果你不想修改 META-INF 文件,或者只想在特定应用中启用,可以在配置文件中指定。

  • 配置项context.initializer.classes

  • 配置示例 (application.properties)

    properties 复制代码
    context.initializer.classes=com.example.CustomApplicationContextInitializer,com.example.AnotherInitializer
  • 配置示例 (application.yml)

    yaml 复制代码
    spring:
      main:
        web-application-type: servlet # 其他配置...
    context:
      initializer:
        classes: com.example.CustomApplicationContextInitializer

    (注:在某些版本中直接写 context.initializer.classes 即可,具体取决于 Spring Boot 版本对配置绑定的支持)

3. 通过 SpringApplication API 编程式注册

main 方法中,手动创建 SpringApplication 对象并调用 addInitializers 方法。这种方式优先级高,且完全由代码控制。

  • 代码示例

    java 复制代码
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        // 添加自定义 initializer
        app.addInitializers(new CustomApplicationContextInitializer());
        // 也可以添加多个
        // app.addInitializers(new AnotherInitializer());
        app.run(args);
    }

4. 通过 SpringApplicationBuilder 链式调用

如果你使用 SpringApplicationBuilder 来构建应用(常用于测试或更复杂的构建场景),可以使用 .initializers() 方法。

  • 代码示例

    java 复制代码
    public static void main(String[] args) {
        new SpringApplicationBuilder(MyApplication.class)
            .initializers(new MyCustomInitializer())
            .run(args);
    }

2. BeanDefinitionRegistryPostProcessor

核心定位:Bean 定义注册阶段,动态注册/修改 Bean 定义(无实例化)

执行时机 :加载 Bean 定义阶段,早于BeanFactoryPostProcessor,此时所有默认 Bean 定义已加载,但未实例化

能拿到什么:BeanDefinitionRegistry(Bean 定义注册器)、ConfigurableListableBeanFactory(Bean 工厂),能操作 Bean 定义(注册、修改、删除)

实战场景:动态扫描包注册 Bean(如 MyBatis Mapper 扫描)、替换框架默认 Bean、条件注册 Bean

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 实战用途:动态注册 Bean,模拟 MyBatis 扫描 Mapper 接口的底层逻辑
 */
@Component // 交给 Spring 管理,自动执行
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 1. 拿到 Bean 定义注册器(核心资源),判断某个 Bean 是否已注册
        boolean hasUserService = registry.containsBeanDefinition("userService");
        System.out.println("userService 是否已注册:" + hasUserService);
        
        // 2. 动态注册一个 Bean(模拟扫描到的 Mapper 接口/自定义组件)
        // 构建 Bean 定义(指定 Bean 类型、作用域等)
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
        builder.setScope("singleton"); // 单例模式
        builder.addPropertyValue("username", "admin"); // 设置属性
        
        // 注册 Bean,Bean 名称为 "customUserService"
        registry.registerBeanDefinition("customUserService", builder.getBeanDefinition());
        System.out.println("动态注册 customUserService 成功");
    }

    // 父接口方法,可用于修改 Bean 工厂配置(可选实现)
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 拿到 Bean 工厂,可修改 Bean 定义的属性(如懒加载)
        beanFactory.getBeanDefinition("customUserService").setLazyInit(false);
        System.out.println("修改 customUserService 懒加载为 false");
    }

    // 模拟自定义组件(被动态注册的 Bean)
    public static class UserService {
        private String username;

        public void setUsername(String username) {
            this.username = username;
        }

        public void sayHello() {
            System.out.println("Hello, " + username);
        }
    }
}

代码说明 :MyBatis 的@MapperScan 底层就是通过该接口实现的------扫描指定包下的接口,动态注册为 Bean 定义,无需手动写 @Bean

触发执行方式 :无需手动注册,只要给实现类添加 @Component 注解(或其他 Spring 组件注解,如 @Service),让 Spring 扫描到,就会自动执行。

3. BeanFactoryPostProcessor

核心定位:Bean 工厂后置处理,配置级修改,无实例化

执行时机 :所有 Bean 定义已加载,但所有 Bean 都还没创建(实例化前)

能拿到什么:ConfigurableListableBeanFactory(Bean 工厂),能获取所有 Bean 定义、修改 Bean 定义的属性

实战场景 :替换配置文件占位符 ${}、修改 Bean 的作用域/懒加载、调整 Bean 属性值、统一配置 Bean 前缀

注意不能在这里实例化 Bean (比如调用 beanFactory.getBean()),会导致 Bean 提前初始化,破坏生命周期顺序。

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 实战用途:修改 Bean 定义属性、替换占位符,统一配置 Bean 行为
 */
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 1. 拿到 Bean 工厂(核心资源),获取所有 Bean 定义名称
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        System.out.println("当前容器中 Bean 定义数量:" + beanDefinitionNames.length);
        
        // 2. 遍历所有 Bean 定义,修改指定 Bean 的属性(实战:统一设置所有 Service 为非懒加载)
        for (String beanName : beanDefinitionNames) {
            if (beanName.endsWith("Service")) { // 匹配所有 Service 结尾的 Bean
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
                // 修改懒加载为 false(立即初始化)
                beanDefinition.setLazyInit(false);
                System.out.println("修改 " + beanName + " 懒加载为 false");
            }
        }
        
        // 3. 模拟替换占位符(实战:动态替换配置文件中的 ${app.version})
        // 这里简化实现,实际底层是 PropertyPlaceholderConfigurer(也是 BeanFactoryPostProcessor)
        BeanDefinition userServiceDef = beanFactory.getBeanDefinition("customUserService");
        String username = (String) userServiceDef.getPropertyValues().getPropertyValue("username").getValue();
        // 替换占位符(模拟从配置文件读取)
        userServiceDef.getPropertyValues().addPropertyValue("username", username.replace("admin", "root"));
        System.out.println("替换 customUserService 的 username 为 root");
    }
}

代码说明 :Spring 内置的 PropertyPlaceholderConfigurer(处理 ${} 占位符)、ConfigurationClassPostProcessor(处理@Configuration),本质都是 BeanFactoryPostProcessor

触发执行方式 :与 BeanDefinitionRegistryPostProcessor 一致,无需手动注册,给实现类添加 @Component 注解,Spring 自动扫描并执行。

4. InstantiationAwareBeanPostProcessor

核心定位:Bean 实例化前/后、依赖注入前的最底层拦截器,Spring 最强大的 Bean 扩展接口

执行时机Bean 实例化之前 → 实例化之后 → 依赖注入之前

能拿到什么:Bean 类型、Bean 名称、Bean 实例(实例化后)、BeanDefinition,能控制实例化过程、替换 Bean 实例

实战场景:自定义 Bean 实例化(如替代默认构造方法)、实现单例/多例外的作用域(如请求域)、跳过 Bean 实例化、AOP 底层依赖(获取 Bean 实例进行代理)

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 实战用途:控制 Bean 实例化过程、替换 Bean 实例,模拟 AOP 底层代理前置操作
 */
@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    // 1. Bean 实例化之前执行(最核心方法),可返回自定义实例,跳过默认实例化
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        // 只拦截 customUserService 这个 Bean
        if ("customUserService".equals(beanName)) {
            System.out.println("Bean 实例化前:" + beanName + ",Bean 类型:" + beanClass.getName());
            // 可选:返回自定义实例,跳过 Spring 默认的实例化(实战:自定义实例化逻辑)
            // return new CustomBeanDefinitionRegistryPostProcessor.UserService();
        }
        return null; // 返回 null,走 Spring 默认实例化
    }

    // 2. Bean 实例化之后、依赖注入之前执行,可修改 Bean 实例
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("customUserService".equals(beanName)) {
            System.out.println("Bean 实例化后:" + beanName + ",实例对象:" + bean);
            // 返回 true:允许依赖注入;返回 false:跳过依赖注入
            return true;
        }
        return true;
    }

    // 3. 依赖注入之前执行,可修改注入的属性值
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("customUserService".equals(beanName)) {
            System.out.println("依赖注入前:修改 " + beanName + " 的属性");
            // 可修改注入的属性(比如动态设置属性值)
            // pvs = new MutablePropertyValues(pvs).addPropertyValue("username", "test");
        }
        return pvs;
    }
}

代码说明 :Spring AOP 的 AnnotationAwareAspectJAutoProxyCreator 底层就是继承该接口,在实例化后、依赖注入前对 Bean 进行代理,这是 AOP 实现的核心步骤。

触发执行方式 :无需手动注册,给实现类添加 @Component注解,Spring 自动扫描,在 Bean 实例化阶段自动回调该接口的方法。

5. Aware 系列接口(BeanNameAware / BeanFactoryAware / ApplicationContextAware)

核心定位:让 Bean 感知容器自身信息,获得容器的核心能力

执行时机 :Bean 实例化后,填充属性(依赖注入)完成,初始化方法(@PostConstruct)之前

能拿到什么

  • BeanNameAware:拿到当前 Bean 的名称(String 类型)
  • BeanFactoryAware:拿到 BeanFactory(Bean 工厂),可手动获取容器内的 Bean
  • ApplicationContextAware:拿到 ApplicationContext(上下文),拥有比 BeanFactory 更丰富的功能(如事件发布、资源加载)

实战场景:在自定义 Bean 中手动获取其他 Bean、加载资源文件、发布事件,是日常开发中最常用的扩展方式之一。

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 实战用途:在自定义 Bean 中获取容器资源、手动获取其他 Bean,日常开发最常用
 */
@Component("myAwareBean")
public class CustomAwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {

    // 1. 从 BeanNameAware 拿到 Bean 名称
    private String beanName;
    // 2. 从 BeanFactoryAware 拿到 Bean 工厂
    private BeanFactory beanFactory;
    // 3. 从 ApplicationContextAware 拿到上下文
    private ApplicationContext applicationContext;

    // BeanNameAware 方法:设置 Bean 名称
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("从 BeanNameAware 拿到 Bean 名称:" + beanName);
    }

    // BeanFactoryAware 方法:设置 Bean 工厂
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("从 BeanFactoryAware 拿到 Bean 工厂:" + beanFactory);
        // 实战:手动获取容器中的 customUserService Bean
        CustomBeanDefinitionRegistryPostProcessor.UserService userService = 
                beanFactory.getBean(CustomBeanDefinitionRegistryPostProcessor.UserService.class);
        userService.sayHello();
    }

    // ApplicationContextAware 方法:设置上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("从 ApplicationContextAware 拿到上下文:" + applicationContext);
        // 实战:获取环境配置(上下文比 BeanFactory 功能更全)
        String appName = applicationContext.getEnvironment().getProperty("app.name");
        System.out.println("从上下文拿到 app.name:" + appName);
        // 实战:发布事件(上下文独有功能)
        applicationContext.publishEvent(new CustomEvent(this, "Aware Bean 初始化完成"));
    }

    // 模拟自定义事件(上下文发布事件示例)
    public static class CustomEvent extends org.springframework.context.ApplicationEvent {
        private String message;

        public CustomEvent(Object source, String message) {
            super(source);
            this.message = message;
        }

        public String getMessage() {
            return message;
        }
    }

    // 事件监听器(接收上面发布的事件)
    @Component
    public static class CustomEventListener implements org.springframework.context.ApplicationListener<CustomEvent> {
        @Override
        public void onApplicationEvent(CustomEvent event) {
            System.out.println("收到事件:" + event.getMessage());
        }
    }
}

代码说明 :日常开发中,如果你需要在一个 Bean 中获取另一个 Bean,又不想用 @Autowired(比如动态获取),就可以通过 BeanFactoryAwareApplicationContextAware 实现,灵活且可控。

触发执行方式 :无需任何手动注册,只要实现该系列接口的 Bean 是由 Spring 容器管理的(如添加 @Component@Bean 注解),Spring 在创建该 Bean 时,会自动调用对应接口的方法(如 setBeanName、setApplicationContext)。

6. @PostConstruct(最常用的初始化方法)

核心定位:Bean 初始化阶段,最常用、最简洁的初始化方法(JSR-250 规范,非 Spring 原生,但 Spring 完全支持)

执行时机 :依赖注入完成后,InitializingBean 之前

能拿到什么:当前 Bean 的所有注入属性、容器资源(如果实现了 Aware 接口),能执行 Bean 的初始化业务逻辑

实战场景:加载初始化数据、初始化数据库连接、启动定时任务、初始化缓存,日常开发 80% 的初始化场景用它就够。

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * 实战用途:Bean 初始化业务逻辑,日常开发最常用
 */
@Component
public class UserDao {

    // 依赖注入(模拟数据库连接池)
    @Autowired
    private DataSource dataSource;

    // 初始化缓存(模拟业务场景)
    private List<String> userCache;

    // 初始化方法:依赖注入完成后执行
    @PostConstruct
    public void init() {
        System.out.println("UserDao 初始化:依赖注入的数据源:" + dataSource);
        // 实战:初始化缓存(从数据库加载数据到内存)
        userCache = new ArrayList<>();
        userCache.add("admin");
        userCache.add("test");
        userCache.add("guest");
        System.out.println("UserDao 缓存初始化完成,缓存数量:" + userCache.size());
        
        // 实战:启动定时任务(模拟定时刷新缓存)
        // ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        // executor.scheduleAtFixedRate(this::refreshCache, 0, 10, TimeUnit.MINUTES);
    }

    // 模拟刷新缓存方法
    public void refreshCache() {
        userCache.clear();
        userCache.add("admin");
        userCache.add("test");
        System.out.println("缓存刷新完成");
    }

    // 模拟数据源(用于依赖注入)
    @Component
    public static class DataSource {
        private String url = "jdbc:mysql://localhost:3306/test";
        private String username = "root";
        private String password = "123456";

        @Override
        public String toString() {
            return "DataSource{" + "url='" + url + ''' + ", username='" + username + ''' + '}';
        }
    }
}

代码说明@PostConstruct 无需实现任何接口,只需在方法上添加注解,简洁高效,是日常开发中初始化 Bean 的首选方式,比 InitializingBean 更灵活。

触发执行方式 :无需手动触发,只要在方法上添加 @PostConstruct 注解,且该 Bean 由 Spring 管理(如添加@Component),Spring 会在 Bean 依赖注入完成后,自动调用该方法。

7. InitializingBean(Spring 原生初始化接口)

核心定位 :Spring 原生的 Bean 初始化接口,功能与 @PostConstruct 几乎一致

执行时机@PostConstruct 之后,自定义 init-method 之前

能拿到什么 :当前 Bean 的所有注入属性、容器资源(如果实现了 Aware 接口),与 @PostConstruct 一致

实战场景 :框架底层初始化(如 Spring 内置组件),日常开发推荐用 @PostConstruct,但需要了解该接口(面试常问)。

执行顺序@PostConstructafterPropertiesSet()(InitializingBean 方法) → 自定义 init-method

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

/**
 * 实战用途:Spring 原生初始化方式,常用于框架底层,演示执行顺序
 */
@Component
public class OrderService implements InitializingBean {

    @Autowired
    private UserDao userDao;

    // 1. @PostConstruct 方法
    @PostConstruct
    public void postConstructInit() {
        System.out.println("1. @PostConstruct 执行:OrderService 初始化");
    }

    // 2. InitializingBean 方法(Spring 原生)
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("2. InitializingBean.afterPropertiesSet 执行:依赖注入的 UserDao:" + userDao);
        // 实战:初始化业务逻辑(与 @PostConstruct 功能一致)
        System.out.println("OrderService 业务初始化完成");
    }

    // 3. 自定义 init-method(XML 或 @Bean 中配置)
    public void customInitMethod() {
        System.out.println("3. 自定义 init-method 执行");
    }

    // 注册方式(如果不用 @Component,用 @Bean 配置 init-method)
    // @Bean(initMethod = "customInitMethod")
    // public OrderService orderService() {
    //     return new OrderService();
    // }
}

代码说明 :该接口的核心是 afterPropertiesSet() 方法,意为"属性设置完成后执行",Spring 底层很多组件(如 DataSourceTransactionManager)都实现了该接口进行初始化。

触发执行方式 :无需手动注册,只要实现InitializingBean 接口,且该 Bean 由 Spring 管理(如添加 @Component),Spring 在 Bean 依赖注入完成后,会自动调用 afterPropertiesSet() 方法。

8. SmartInitializingSingleton

核心定位:所有单例 Bean 创建完成后,容器即将就绪前的最后一步初始化

执行时机所有单例 Bean 都实例化、初始化完成,容器就绪之前,是单例 Bean 初始化的最后一步

能拿到什么:容器内所有单例 Bean(可通过 BeanFactory/ApplicationContext 获取),能执行全局初始化操作

实战场景:全局缓存预热、框架启动后校验(如检查所有 Bean 是否符合规范)、事件广播(所有 Bean 就绪后发布)

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

/**
 * 实战用途:所有单例 Bean 就绪后,执行全局初始化、缓存预热
 */
@Component
public class CustomSmartInitializingSingleton implements SmartInitializingSingleton {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private UserDao userDao;

    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("所有单例 Bean 已初始化完成,开始执行全局操作");
        
        // 1. 拿到所有单例 Bean 名称,校验 Bean 规范(实战:检查所有 Service 都有 @Service 注解)
        String[] singletonBeanNames = applicationContext.getBeanDefinitionNames();
        int serviceCount = 0;
        for (String beanName : singletonBeanNames) {
            if (applicationContext.getType(beanName) != null 
                    && applicationContext.getType(beanName).isAnnotationPresent(Component.class)) {
                serviceCount++;
            }
        }
        System.out.println("容器中单例 Bean 数量:" + singletonBeanNames.length + ",Component 注解 Bean 数量:" + serviceCount);
        
        // 2. 全局缓存预热(实战:调用 UserDao 加载缓存,确保容器就绪后缓存可用)
        userDao.refreshCache();
        System.out.println("全局缓存预热完成");
        
        // 3. 校验核心 Bean 是否存在(实战:确保数据源、事务管理器等核心组件已初始化)
        boolean hasDataSource = applicationContext.containsBean("dataSource");
        System.out.println("核心组件 dataSource 是否存在:" + hasDataSource);
    }
}

代码说明:该接口的核心优势是"等待所有单例 Bean 就绪",比如你有一个组件需要依赖多个其他 Bean 初始化完成后才能执行,用该接口最合适,避免出现"依赖 Bean 未初始化"的问题。

触发执行方式 :无需手动注册,给实现类添加 @Component 注解,Spring 会在所有单例 Bean 实例化、初始化完成后,自动调用 afterSingletonsInstantiated() 方法。

9. BeanPostProcessor(AOP、代理、增强核心)

核心定位:Bean 初始化前后的增强器,Spring 最核心的增强接口,AOP、事务、日志等功能的底层实现

执行时机@PostConstructInitializingBean 等初始化方法之前 → 初始化方法之后

能拿到什么:Bean 实例、Bean 名称,能对 Bean 实例进行增强、替换(如创建代理对象)

实战场景:AOP 代理、事务管理、日志记录、性能监控、权限校验,几乎所有 Spring 增强功能都依赖该接口。

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

/**
 * 实战用途:Bean 增强、AOP 代理、日志监控,模拟 Spring AOP 底层逻辑
 */
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    // 1. Bean 初始化方法(@PostConstruct、afterPropertiesSet)之前执行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 只增强 Service 结尾的 Bean
        if (beanName.endsWith("Service")) {
            System.out.println("初始化前增强:" + beanName + ",Bean 实例:" + bean);
            // 实战:日志记录(记录 Bean 初始化开始)
        }
        return bean; // 返回原 Bean,不修改
    }

    // 2. Bean 初始化方法之后执行,核心增强方法(可返回代理对象)
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 只增强 OrderService
        if ("orderService".equals(beanName)) {
            System.out.println("初始化后增强:" + beanName + ",开始创建代理对象");
            // 实战:用 CGLIB 创建代理对象,实现 AOP 增强(日志、监控)
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(bean.getClass());
            enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
                // 前置增强:日志记录、性能监控
                long start = System.currentTimeMillis();
                System.out.println("方法 " + method.getName() + " 开始执行");
                
                // 执行原方法
                Object result = proxy.invokeSuper(obj, args);
                
                // 后置增强:记录执行时间
                long end = System.currentTimeMillis();
                System.out.println("方法 " + method.getName() + " 执行完成,耗时:" + (end - start) + "ms");
                return result;
            });
            // 返回代理对象,替换原 Bean
            return enhancer.create();
        }
        return bean; // 其他 Bean 返回原实例
    }
}

代码说明 :Spring AOP 的核心就是通过 BeanPostProcessor 在 Bean 初始化后创建代理对象,将切面逻辑织入到原方法中。上面的代码模拟了 AOP 的底层实现,通过 CGLIB 代理 OrderService,实现方法执行日志和耗时统计。

触发执行方式 :无需手动注册,给实现类添加 @Component 注解,Spring 自动扫描,在每个 Bean 初始化前后,都会自动调用该接口的两个方法。

10. DisposableBean / @PreDestroy(容器销毁阶段)

核心定位:容器销毁时,Bean 的资源释放接口,实现优雅停机

执行时机:应用关闭、容器销毁时(如 Tomcat 停止、Spring Boot 应用 shutdown)

能拿到什么:当前 Bean 实例、容器资源(如果实现了 Aware 接口),能执行资源释放逻辑

实战场景:关闭线程池、断开数据库连接、释放文件句柄、保存数据(如缓存写入数据库)、优雅停机清理

执行顺序@PreDestroydestroy()(DisposableBean 方法) → 自定义 destroy-method

实战代码(可直接运行)

java 复制代码
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 实战用途:容器销毁时释放资源,实现优雅停机
 */
@Component
public class ResourceManager implements DisposableBean {

    // 模拟线程池(需要在容器销毁时关闭)
    private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    // 模拟数据库连接(需要在容器销毁时断开)
    private final UserDao.DataSource dataSource = new UserDao.DataSource();

    // 1. @PreDestroy 方法(日常开发首选)
    @PreDestroy
    public void preDestroyRelease() {
        System.out.println("1. @PreDestroy 执行:开始释放资源");
        // 关闭线程池(优雅关闭,等待所有任务执行完成)
        executorService.shutdown();
        System.out.println("线程池已关闭");
    }

    // 2. DisposableBean 方法(Spring 原生)
    @Override
    public void destroy() throws Exception {
        System.out.println("2. DisposableBean.destroy 执行:释放剩余资源");
        // 断开数据库连接(模拟)
        System.out.println("数据库连接已断开:" + dataSource);
        // 保存缓存数据到数据库(实战场景)
        System.out.println("缓存数据已写入数据库,资源释放完成");
    }

    // 3. 自定义 destroy-method(可选)
    public void customDestroyMethod() {
        System.out.println("3. 自定义 destroy-method 执行:最终清理");
    }

    // 注册方式(如果不用 @Component,用 @Bean 配置 destroy-method)
    // @Bean(destroyMethod = "customDestroyMethod")
    // public ResourceManager resourceManager() {
    //     return new ResourceManager();
    // }
}

代码说明:在生产环境中,优雅停机至关重要,该接口能确保容器关闭时,所有资源都能被正确释放,避免出现线程泄漏、数据库连接未关闭、数据丢失等问题。

触发执行方式 :无需手动触发,只要满足两个条件即可自动执行:1. 实现 DisposableBean 接口或给方法添加 @PreDestroy 注解;2. 该 Bean 由 Spring 管理;3. 应用正常关闭(如执行 shutdown 命令、停止 Tomcat 服务)。

补充:扩展接口触发判断速查表

如果你想快速判断一个扩展点怎么触发,记住这个简单表,开发时直接查,不用记:

扩展点 是否需要注册 触发方式
ApplicationContextInitializer 需要 SpringApplication 手动 add 或 application.yml 配置
BeanDefinitionRegistryPostProcessor 不需要 @Component 注解,Spring 自动扫描执行
BeanFactoryPostProcessor 不需要 @Component 注解,Spring 自动扫描执行
InstantiationAwareBeanPostProcessor 不需要 @Component 注解,Spring 自动扫描执行
Aware 接口 不需要 Bean 由 Spring 管理,自动回调接口方法
@PostConstruct 不需要 Bean 由 Spring 管理,依赖注入后自动执行注解方法
InitializingBean 不需要 Bean 由 Spring 管理,自动调用 afterPropertiesSet 方法
SmartInitializingSingleton 不需要 @Component 注解,所有单例 Bean 就绪后自动执行
BeanPostProcessor 不需要 @Component 注解,Spring 自动扫描,每个 Bean 初始化前后回调
@PreDestroy / DisposableBean 不需要 Bean 由 Spring 管理,应用关闭、容器销毁时自动执行

核心规律:只要是 Spring 组件(加 @Component、@Bean、@Service 等),大部分扩展点都会自动触发;只有 ApplicationContextInitializer 需要手动注册,这是唯一例外。

三、全景执行顺序

java 复制代码
1. ApplicationContextInitializer(容器刷新前,最早)
2. BeanDefinitionRegistryPostProcessor(Bean 定义注册,动态加 Bean)
3. BeanFactoryPostProcessor(Bean 工厂后置处理,改 Bean 定义)
4. InstantiationAwareBeanPostProcessor(Bean 实例化前/后、依赖注入前)
5. Aware 接口(BeanNameAware/BeanFactoryAware/ApplicationContextAware,感知容器)
6. @PostConstruct(Bean 初始化,最常用)
7. InitializingBean(Spring 原生初始化)
8. BeanPostProcessor(初始化前后,AOP 代理)
9. SmartInitializingSingleton(所有单例 Bean 就绪后)
10. @PreDestroy / DisposableBean(容器销毁,释放资源)

四、实战速查表(开发时直接查,不用记)

需求场景 推荐接口 能拿到什么核心资源
环境配置、激活 Profile、配置中心拉取 ApplicationContextInitializer ConfigurableApplicationContext、Environment
动态注册 Bean、扫描包(如 MyBatis Mapper) BeanDefinitionRegistryPostProcessor BeanDefinitionRegistry、BeanFactory
修改 Bean 配置、替换占位符 BeanFactoryPostProcessor ConfigurableListableBeanFactory
控制 Bean 实例化、替换 Bean 实例 InstantiationAwareBeanPostProcessor Bean 类型、Bean 名称、Bean 实例
在 Bean 中获取容器、手动拿其他 Bean ApplicationContextAware / BeanFactoryAware ApplicationContext、BeanFactory
Bean 初始化、加载数据、启动定时任务 @PostConstruct
相关推荐
吾诺2 小时前
Spring Boot--@PathVariable、@RequestParam、@RequestBody
java·spring boot·后端
jiankeljx2 小时前
Spring Boot实现多数据源连接和切换
spring boot·后端·oracle
xyyaihxl3 小时前
springboot与springcloud对应版本
java·spring boot·spring cloud
小箌4 小时前
springboot_01
java·spring boot·后端
a8a3024 小时前
Springboot中CommandLineRunner的用法以及执行顺序的控制
java·spring boot·spring
sevenlin4 小时前
Spring Boot 经典九设计模式全览
java·spring boot·设计模式
salipopl4 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
Java水解5 小时前
Spring Boot 数据仓库与ETL工具集成
spring boot·后端
beata5 小时前
Spring Boot基础-3:Spring Boot 4.x 配置文件全攻略与多环境切换
spring boot·后端