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

12 阅读20分钟

本文专注讲解 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 版本实现而定,建议避免重复注册。

实战代码(可直接运行)

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)
    org.springframework.context.ApplicationContextInitializer=\
    com.example.CustomApplicationContextInitializer
    
  • 配置内容 (Spring Boot 3+ .imports)
    com.example.CustomApplicationContextInitializer
    
  • 触发时机SpringApplication 构造过程中,通过 SpringFactoriesLoader 自动加载。

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

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

  • 配置项context.initializer.classes
  • 配置示例 (application.properties)
    context.initializer.classes=com.example.CustomApplicationContextInitializer,com.example.AnotherInitializer
    
  • 配置示例 (application.yml)
    spring:
      main:
        web-application-type: servlet # 其他配置...
    context:
      initializer:
        classes: com.example.CustomApplicationContextInitializer
    
    (注:在某些版本中直接写 context.initializer.classes 即可,具体取决于 Spring Boot 版本对配置绑定的支持)

3. 通过 SpringApplication API 编程式注册

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

  • 代码示例
    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() 方法。

  • 代码示例
    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

实战代码(可直接运行)

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 提前初始化,破坏生命周期顺序。

实战代码(可直接运行)

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 实例进行代理)

实战代码(可直接运行)

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、加载资源文件、发布事件,是日常开发中最常用的扩展方式之一。

实战代码(可直接运行)

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% 的初始化场景用它就够。

实战代码(可直接运行)

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

实战代码(可直接运行)

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 就绪后发布)

实战代码(可直接运行)

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 增强功能都依赖该接口。

实战代码(可直接运行)

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

实战代码(可直接运行)

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 需要手动注册,这是唯一例外。

三、全景执行顺序

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、配置中心拉取ApplicationContextInitializerConfigurableApplicationContext、Environment
动态注册 Bean、扫描包(如 MyBatis Mapper)BeanDefinitionRegistryPostProcessorBeanDefinitionRegistry、BeanFactory
修改 Bean 配置、替换占位符BeanFactoryPostProcessorConfigurableListableBeanFactory
控制 Bean 实例化、替换 Bean 实例InstantiationAwareBeanPostProcessorBean 类型、Bean 名称、Bean 实例
在 Bean 中获取容器、手动拿其他 BeanApplicationContextAware / BeanFactoryAwareApplicationContext、BeanFactory
Bean 初始化、加载数据、启动定时任务@PostConstruct