Spring源码 第十一篇:Spring 扩展点全解析 - 从容器启动到 Bean 生命周期的完整执行时序

前言

前面 10 篇,我们拆解了 IOC、Bean 生命周期、AOP、事务、SpringMVC、Boot 自动配置、环境配置、事件、类型转换。Spring 所有高阶能力、第三方框架整合(MyBatis、Feign、Dubbo),全部依赖 Spring 预留的扩展钩子。本章内容相对枯燥,到了从入门到放弃的阶段了 O(∩_∩)O。

接下来让我开始枯燥的旅程吧!!!

一、容器启动阶段扩展(Bean 还没创建)

1. BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor,因此它既是 BeanDefinitionRegistryPostProcessor 也是 BeanFactoryPostProcessor。Spring 容器的执行顺序如下:

  1. 首先执行所有实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry() 方法。
  2. 然后执行所有实现了 Ordered 接口的。
  3. 接着执行其他所有的 BeanDefinitionRegistryPostProcessor
  4. 之后,才会执行上述所有实现了 PriorityOrderedOrdered 以及其他 BeanDefinitionRegistryPostProcessorpostProcessBeanFactory() 方法(这是来自其父接口 BeanFactoryPostProcessor 的方法)。
  5. 最后,才轮到其他只实现了 BeanFactoryPostProcessor 接口的普通后置处理器。

核心源码位置:

java 复制代码
// PostProcessorRegistrationDelegate
invokeBeanFactoryPostProcessors(beanFactory);

核心能力:

  • 拥有 BeanDefinitionRegistry 能力
  • 可以手动 registry.registerBeanDefinition()
  • 核心作用:动态扫描、动态注册 Bean 定义,不用写 @Component

经典落地案例:

  • MyBatis:MapperScannerConfigurer 扫描 Mapper 接口
  • Feign:批量注册 Feign 接口 BeanDefinition

代码示例:

java 复制代码
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 这一步可以动态注册 BeanDefinition,例如:
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyService.class);
        registry.registerBeanDefinition("myService", builder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 这里的执行时机晚于 postProcessBeanDefinitionRegistry,但早于普通 BeanFactoryPostProcessor
        // 注意:此时不能获取尚未完全初始化的 Bean 实例,仅能操作 BeanFactory。
    }
}

典型框架落地案例:

MyBatis‑Spring 的 MapperScannerConfigurer 就是通过实现 BeanDefinitionRegistryPostProcessor,在 postProcessBeanDefinitionRegistry() 中扫描 Mapper 接口,并动态注册 MapperFactoryBean 的 BeanDefinition,从而实现无需手动配置每个 Mapper。

⚠️ 陷阱提醒:

如果同时需要实现 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,建议直接实现前者(因为已继承后者),并务必实现 postProcessBeanDefinitionRegistry 方法,不要只重写 postProcessBeanFactory,否则无法执行注册阶段的逻辑。

2. BeanFactoryPostProcessor

执行时机: BeanDefinition 全部加载完成,Bean 还没有实例化

核心区别:

  • BeanFactoryPostProcessor 的主要职责是修改已注册的 BeanDefinition(比如修改属性值、作用域等)。
  • BeanDefinitionRegistryPostProcessor 则专注于新增或动态注册 BeanDefinition。

经典落地:
ConfigurationClassPostProcessor 解析 @Configuration@Bean@Import、组件扫描是 Spring 全注解开发的核心底层。

区别口诀:

  • BeanDefinitionRegistryPostProcessor 👉 注册 Bean
  • BeanFactoryPostProcessor 👉 修改 Bean 定义

二、Bean 生命周期级扩展(最核心、面试最重)

1. BeanPostProcessor

执行时机: Bean 实例化 + 属性填充完成后

两个关键方法:

  1. postProcessBeforeInitialization:初始化方法之前,在 Bean 执行了 @PostConstructafterPropertiesSet() 以及自定义 init-method 之前调用。
  2. postProcessAfterInitialization:初始化方法之后,在以上所有初始化回调全部完成之后调用。

顺序控制: BeanPostProcessor 的排序依据是 PriorityOrderedOrdered 接口,而不是 @Order 注解。@Order 注解主要影响的是组件在被注入到集合时的存储顺序,并不能用于定义 BeanPostProcessor 的执行优先级。

核心源码位置: AbstractAutowireCapableBeanFactory#initializeBean()

java 复制代码
// 前置处理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 初始化方法执行
invokeInitMethods(beanName, wrappedBean, mbd);
// 后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

核心作用: 拦截所有 Bean,包装、替换、代理、增强。

经典落地:

  • AOP 代理创建:AnnotationAwareAspectJAutoProxyCreator
  • 依赖注入:AutowiredAnnotationBeanPostProcessor 处理 @Autowired@Value
  • 事务代理、动态代理全部依靠它
1.1 InstantiationAwareBeanPostProcessor 的隐藏陷阱

⚠️ 关键陷阱: 如果 postProcessAfterInstantiation 方法返回 false,Spring 会跳过对该 Bean 实例的属性填充(populateBean),并且后续的 InstantiationAwareBeanPostProcessor 实例也不会再被调用。但请注意,其他普通的 BeanPostProcessor(如用于 AOP 的代理创建)仍然会被正常执行。

示例代码:

java 复制代码
@Component
public class MyInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof SomeSpecialBean) {
            // 对于某种特殊 Bean,我们决定手动处理属性,跳过自动填充
            return false;
        }
        return true; // 绝大多数情况应返回 true
    }
}
1.2 BeanPostProcessor 注册的危险误区

🚨 非常容易出错的注册方式:

@Configuration 类中,如果使用非静态 @Bean 方法声明一个 BeanPostProcessor,Spring 会过早地创建它依赖的其他 Bean,从而破坏正常的 Bean 实例化顺序,导致容器启动失败或循环依赖。

正确做法:

  1. 将该 @Bean 方法声明为 static,或
  2. BeanPostProcessor 实现类直接用 @Component 注解并确保组件扫描路径包含它。

错误示例:

java 复制代码
@Configuration
public class AppConfig {
    @Bean // ❌ 非静态方法,会导致 MyBeanPostProcessor 依赖的 bean 被提前创建
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

如果用非静态方法注册它们:Spring 必须先实例化你的配置类 → 才能调用方法创建后置处理器但后置处理器是用来初始化配置类的 → 死循环 / 提前初始化 / 配置不生效

正确示例:

java 复制代码
@Configuration
public class AppConfig {
    @Bean
    public static MyBeanPostProcessor myBeanPostProcessor() { // ✅ 静态方法
        return new MyBeanPostProcessor();
    }
}

2. InitializingBean + @PostConstruct + init-method

执行顺序: @PostConstructInitializingBean#afterPropertiesSet() → 自定义 init-method

源码位置: AbstractAutowireCapableBeanFactory#invokeInitMethods

作用: 单个 Bean 初始化业务逻辑,无全局影响。

3. DisposableBean + destroy-method

执行时机: 容器关闭、单例 Bean 销毁

源码位置: DefaultSingletonBeanRegistry#destroySingletons()

4. FactoryBean

底层接口:

java 复制代码
public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
}

作用: 用来构建复杂、重对象,屏蔽复杂创建逻辑。容器最终存的是 getObject() 返回的对象。

经典落地:

  • MyBatis:SqlSessionFactoryBean
  • 连接池、中间件复杂 Bean 构建

三、注解驱动扩展(自动配置核心)

1. ImportSelector

执行时机: 解析 @Import 时执行

分类:

  1. 普通 ImportSelector
  2. DeferredImportSelector 延迟导入(所有配置类解析完再执行)

核心落地: SpringBoot 自动配置:AutoConfigurationImportSelector 加载所有自动配置类

2. ImportBeanDefinitionRegistrar

执行时机: 配置类解析阶段

作用: 手动编码批量注册 BeanDefinition,不限制注解、不限制扫描路径。

经典落地:

  • @MapperScan
  • @EnableFeignClients
  • 所有 Enable 开头的开关注解底层基本都靠它

四、事件 & 环境扩展

1. ApplicationListener / @EventListener

源码入口: AbstractApplicationContext#publishEvent()

作用: 容器刷新、启动、关闭、自定义业务事件解耦神器

2. EnvironmentPostProcessor

执行时机: SpringBoot 最早环境准备阶段

作用: 自定义加载配置文件、扩展配置源,对应第 8 篇 Environment 体系。

五、SpringMVC 专属扩展(Web 层)

对应第 6 篇 MVC 完整流程

  1. HandlerInterceptorpreHandle / postHandle / afterCompletion
  2. HandlerMethodArgumentResolver:自定义参数解析,实现自定义注解参数
  3. HandlerMethodReturnValueHandler:统一返回值封装、全局响应处理
  4. WebMvcConfigurer:跨域、拦截器、资源映射、消息转换器配置

六、全网必背:Spring 扩展点完整执行时序

  1. EnvironmentPostProcessor 👉 环境配置早期扩展
  2. BeanDefinitionRegistryPostProcessor 👉 动态注册 Bean
  3. BeanFactoryPostProcessor 👉 修改 BeanDefinition
  4. Bean 实例化 + 依赖填充
  5. BeanPostProcessor#Before
  6. @PostConstruct
  7. InitializingBean#afterPropertiesSet
  8. 自定义 init-method
  9. BeanPostProcessor#After 👉 AOP 代理、最终 Bean 成品
  10. 容器刷新完成:ContextRefreshedEvent
  11. 容器关闭:DisposableBean / destroy

七、场景选型(工作直接对照用)

需求场景 推荐扩展点
要动态造 Bean、扫接口、中间件整合 ImportBeanDefinitionRegistrar / BeanDefinitionRegistryPostProcessor
要修改全局 Bean 定义、动态配置 BeanFactoryPostProcessor
要给所有 Bean 做代理、增强、注入 BeanPostProcessor
复杂对象创建、组装 FactoryBean
自动配置、批量导入配置类 DeferredImportSelector
解耦、异步事件、业务解耦 ApplicationListener
相关推荐
开源推荐官10 小时前
2026 商城系统源码实测,真正适合二开的系统有哪些?
java·架构·开源
云烟成雨TD10 小时前
Spring AI 1.x 系列【58】提示词工程(Prompt Engineering)
java·人工智能·spring
總鑽風10 小时前
[特殊字符] Spring AI Alibaba企业级智能助手落地实践
java·人工智能·spring
Flittly10 小时前
【AgentScope Java新手村系列】(1)框架简介与环境搭建
java·spring boot·笔记·spring·ai
一条泥憨鱼10 小时前
DTO、VO、PO、BO 到底该怎么区分?
java·数据库·状态模式·对象·印象笔记·对象类型
唐青枫10 小时前
Java Spring Data JPA 实战指南:Repository 查询、分页与实体映射
java
2601_9618454210 小时前
2026四级作文预测26年|英语四级写作范文+模板PDF
java·数据库·spring·eclipse·pdf·tomcat·hibernate
wuminyu11 小时前
Java锁机制之park与futex系统级协同机制解析
java·linux·c语言·jvm·c++
疯狂打码的少年11 小时前
编译程序与解释程序的区别
java·开发语言·笔记
xieliyu.18 小时前
Java算法精讲:双指针(三)
java·开发语言·算法