Spring Boot 中关于 Bean 加载、实例化、初始化全生命周期的扩展点

13 阅读7分钟

一、先明确:Bean 完整生命周期

先梳理 Spring Bean 从“定义”到“销毁”的完整流程,所有扩展点都嵌入在这个流程中:

1. 扫描/解析生成 BeanDefinition(Bean 定义)→ 2. 注册 BeanDefinition 到容器 → 3. 实例化 Bean(创建对象)→ 4. 属性填充(依赖注入)→ 5. 初始化前处理 → 6. 初始化(执行 init 方法)→ 7. 初始化后处理 → 8. Bean 就绪使用 → 9. 容器关闭 → 10. 销毁 Bean

二、按生命周期阶段拆解扩展点(优先级+时机+示例)

阶段 1:BeanDefinition 处理阶段(实例化前,最高优先级)

核心目标:修改/新增/删除 BeanDefinition,不涉及 Bean 实例
该阶段扩展点优先级:BeanDefinitionRegistryPostProcessor > BeanFactoryPostProcessor

1. BeanDefinitionRegistryPostProcessor(顶级扩展点)

  • 核心作用:动态注册/修改/删除 BeanDefinition(Spring 最早的扩展点)
  • 执行时机:扫描生成 BeanDefinition 后 → Bean 实例化前
  • 优先级:最高(优先于所有 BeanFactoryPostProcessor)
  • 典型场景:Spring Boot 自动配置、MyBatis Mapper 扫描、动态注册 Bean

实战示例:动态注册 UserService Bean

@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 1. 构建 BeanDefinition(描述 UserService 的定义)
        RootBeanDefinition userServiceDefinition = new RootBeanDefinition(UserService.class);
        // 可选:设置 Bean 属性(如作用域、初始化方法)
        userServiceDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        userServiceDefinition.setInitMethodName("init");
        
        // 2. 注册 BeanDefinition 到容器(Bean 名称:userService)
        registry.registerBeanDefinition("userService", userServiceDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 可选:对 BeanFactory 做额外配置(优先级低于上面的方法)
        beanFactory.registerSingleton("testBean", new TestBean());
    }
}

// 无任何 Spring 注解的业务类
public class UserService {
    public void init() {
        System.out.println("UserService 初始化方法执行");
    }
    
    public void sayHello() {
        System.out.println("动态注册的 UserService 就绪");
    }
}

// 测试
@SpringBootApplication
public class TestApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class);
        UserService userService = context.getBean(UserService.class);
        userService.sayHello(); // 输出:动态注册的 UserService 就绪
    }
}

2. BeanFactoryPostProcessor(BeanFactory 配置修改)

  • 核心作用:修改已注册的 BeanDefinition 属性(如修改作用域、属性值),不能新增 BeanDefinition
  • 执行时机:BeanDefinitionRegistryPostProcessor 执行后 → Bean 实例化前
  • 优先级:低于 BeanDefinitionRegistryPostProcessor
  • 典型场景:修改 Bean 配置、占位符替换(如 ${spring.datasource.url})

实战示例:修改已有 BeanDefinition 的属性

@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 1. 获取已注册的 BeanDefinition(假设容器中有 "userService" Bean)
        BeanDefinition userServiceDef = beanFactory.getBeanDefinition("userService");
        
        // 2. 修改属性:将单例改为原型
        userServiceDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        
        // 3. 设置自定义属性
        MutablePropertyValues propertyValues = userServiceDef.getPropertyValues();
        propertyValues.add("name", "自定义名称");
    }
}

阶段 2:Bean 实例化+属性填充阶段(初始化前)

核心目标:干预 Bean 实例的创建和依赖注入
该阶段扩展点:InstantiationAwareBeanPostProcessor(BeanPostProcessor 子接口)

InstantiationAwareBeanPostProcessor(实例化+属性填充拦截)

  • 核心作用:拦截 Bean 实例化、属性填充过程,可替换 Bean 实例、修改注入属性
  • 执行时机
    1. postProcessBeforeInstantiation:Bean 实例化前(替代默认实例化逻辑)
    2. postProcessAfterInstantiation:Bean 实例化后 → 属性填充前
    3. postProcessProperties:属性填充时(修改注入的属性值)
  • 优先级:高于普通 BeanPostProcessor
  • 典型场景:自定义依赖注入、字段注解解析(如 @Value、@Autowired)

实战示例:拦截 UserService 实例化和属性填充

@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    // 1. 实例化前拦截(可直接返回自定义实例,跳过默认实例化)
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService 实例化前拦截");
            // 可选:返回自定义实例(替代 Spring 自动实例化)
            // return new UserService();
        }
        return null; // 返回 null 则走默认实例化逻辑
    }

    // 2. 实例化后拦截(属性填充前)
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService 实例化后,属性填充前");
        }
        return true; // 返回 true 才会执行属性填充
    }

    // 3. 属性填充拦截(修改注入的属性值)
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService 属性填充拦截");
            // 修改属性值(假设 UserService 有 name 字段)
            MutablePropertyValues mutablePvs = (MutablePropertyValues) pvs;
            mutablePvs.add("name", "拦截后修改的名称");
        }
        return pvs;
    }
}

阶段 3:Bean 初始化阶段(实例化+属性填充后)

核心目标:修改 Bean 实例、执行初始化逻辑
该阶段扩展点优先级:BeanPostProcessor.postProcessBeforeInitialization > 自定义初始化方法 > BeanPostProcessor.postProcessAfterInitialization

1. BeanPostProcessor(初始化前后拦截)

  • 核心作用:拦截所有 Bean 的初始化过程,修改 Bean 实例
  • 执行时机
    1. postProcessBeforeInitialization:初始化方法(如 @PostConstruct、init-method)执行前
    2. postProcessAfterInitialization:初始化方法执行后
  • 优先级:可通过 @Order 注解控制多个 BeanPostProcessor 的执行顺序
  • 典型场景:AOP 代理创建、Bean 增强(如事务代理、缓存代理)

实战示例:拦截 UserService 初始化过程

@Component
@Order(1) // 控制优先级(数字越小优先级越高)
public class CustomBeanPostProcessor implements BeanPostProcessor {
    // 1. 初始化前处理
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService 初始化前处理");
        }
        return bean; // 返回修改后的 Bean 实例
    }

    // 2. 初始化后处理(AOP 代理通常在这里创建)
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("UserService 初始化后处理");
            // 可选:返回代理对象(如 JDK 动态代理)
            // return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (proxy, method, args) -> {
            //     System.out.println("方法执行前增强");
            //     return method.invoke(bean, args);
            // });
        }
        return bean;
    }
}

2. 自定义初始化方法(3 种方式)

  • 核心作用:执行 Bean 专属的初始化逻辑
  • 执行时机:BeanPostProcessor 前置处理后 → 后置处理前
  • 优先级:同一 Bean 内优先级:@PostConstruct > InitializingBean.afterPropertiesSet() > init-method

实战示例:3 种初始化方法对比

@Component
public class UserService implements InitializingBean {
    private String name;

    // 方式 1:@PostConstruct 注解(最常用)
    @PostConstruct
    public void postConstructInit() {
        System.out.println("UserService @PostConstruct 初始化");
    }

    // 方式 2:实现 InitializingBean 接口
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("UserService InitializingBean 初始化");
    }

    // 方式 3:XML/注解指定 init-method(传统方式)
    public void initMethod() {
        System.out.println("UserService init-method 初始化");
    }

    // getter/setter 省略
}

// 配置类指定 init-method(如果不用注解的话)
@Configuration
public class AppConfig {
    @Bean(initMethod = "initMethod")
    public UserService userService() {
        return new UserService();
    }
}

阶段 4:Bean 销毁阶段(容器关闭时)

核心目标:执行 Bean 销毁前的清理逻辑
扩展点优先级:@PreDestroy > DisposableBean.destroy() > destroy-method

自定义销毁方法(3 种方式)

  • 核心作用:释放资源(如关闭连接池、销毁线程)
  • 执行时机:Spring 容器关闭时(调用 context.close()
  • 典型场景:资源清理、连接关闭

实战示例:3 种销毁方法对比

@Component
public class UserService implements DisposableBean {
    // 方式 1:@PreDestroy 注解
    @PreDestroy
    public void preDestroy() {
        System.out.println("UserService @PreDestroy 销毁");
    }

    // 方式 2:实现 DisposableBean 接口
    @Override
    public void destroy() throws Exception {
        System.out.println("UserService DisposableBean 销毁");
    }

    // 方式 3:XML/注解指定 destroy-method
    public void destroyMethod() {
        System.out.println("UserService destroy-method 销毁");
    }
}

// 配置类指定 destroy-method
@Configuration
public class AppConfig {
    @Bean(destroyMethod = "destroyMethod")
    public UserService userService() {
        return new UserService();
    }
}

// 测试销毁
public class TestDestroy {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class);
        // 关闭容器触发销毁
        context.close();
    }
}

三、所有扩展点优先级总览(从高到低)

扩展点/方法执行阶段核心能力
BeanDefinitionRegistryPostProcessorBeanDefinition 注册后新增/修改/删除 BeanDefinition
BeanFactoryPostProcessorBeanDefinition 处理后修改 BeanDefinition 属性
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiationBean 实例化前替换 Bean 实例
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiationBean 实例化后控制是否执行属性填充
InstantiationAwareBeanPostProcessor.postProcessProperties属性填充时修改注入的属性值
BeanPostProcessor.postProcessBeforeInitialization初始化前Bean 实例增强(如赋值)
@PostConstruct初始化中(最高)注解式初始化逻辑
InitializingBean.afterPropertiesSet()初始化中(中间)接口式初始化逻辑
init-method初始化中(最低)配置式初始化逻辑
BeanPostProcessor.postProcessAfterInitialization初始化后Bean 代理创建(如 AOP)
@PreDestroy销毁前(最高)注解式销毁逻辑
DisposableBean.destroy()销毁前(中间)接口式销毁逻辑
destroy-method销毁前(最低)配置式销毁逻辑

四、典型应用场景总结

业务需求推荐扩展点
动态注册 BeanBeanDefinitionRegistryPostProcessor
修改 Bean 配置(如作用域)BeanFactoryPostProcessor
自定义依赖注入/拦截实例化InstantiationAwareBeanPostProcessor
Bean 增强(如 AOP、缓存)BeanPostProcessor(后置初始化)
Bean 专属初始化逻辑@PostConstruct / InitializingBean
资源清理/连接关闭@PreDestroy / DisposableBean

五、关键注意事项

  1. 避免提前实例化 Bean:在 BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor 中,不要调用 beanFactory.getBean(),否则会触发 Bean 提前实例化,导致扩展点失效;
  2. 优先级控制:多个同类型扩展点可通过 @Order 注解或实现 Ordered 接口控制执行顺序(数字越小优先级越高);
  3. 性能影响:顶级扩展点(如 BeanDefinitionRegistryPostProcessor)执行时机早,复杂逻辑会影响容器启动速度;
  4. 代理对象注意:BeanPostProcessor 后置处理返回的代理对象,才是容器最终使用的 Bean 实例。

总结

  1. 核心逻辑:Spring Bean 扩展点围绕“定义-实例化-初始化-销毁”全生命周期设计,越靠前的扩展点越能影响 Bean 的“定义”,越靠后的扩展点越能影响 Bean 的“实例”;
  2. 优先级核心BeanDefinitionRegistryPostProcessor 是最高优先级扩展点,可动态注册 Bean;BeanPostProcessor 是最常用扩展点,可增强 Bean 实例;
  3. 实战选型:根据需求选择对应阶段的扩展点——改定义用前序扩展点,改实例用后序扩展点;
  4. 核心价值:这些扩展点是 Spring 灵活性的核心体现,Spring Boot 自动配置、MyBatis/Dubbo 整合 Spring 都基于这些扩展点实现。

掌握这些扩展点,你不仅能读懂 Spring 底层源码,还能自定义灵活的 Bean 管理逻辑,比如封装自己的 Starter、实现自定义注解解析等。