Junki
Junki
Published on 2025-12-09 / 4 Visits
0
0

Spring Boot 框架扩展点图解与示例

Spring Boot 的核心优势之一是**“约定大于配置”**,但在实际开发中,我们往往需要基于业务场景定制化扩展框架行为。这些可扩展的入口被称为“扩展点”,它们分布在 Spring Boot 启动、Bean 生命周期、Web 处理、配置加载等核心流程中。

本文将通过流程图解 + 扩展点定位 + 用法示例,系统梳理 Spring Boot 所有核心扩展点,帮助你精准掌握框架定制化的关键入口。

一、先理清核心脉络:Spring Boot 启动流程

理解扩展点的前提是掌握 Spring Boot 启动的核心流程,所有扩展点都依附于这个流程的关键节点:

【启动入口】
  ↓
SpringApplication.run()
  ↓
1. 初始化 SpringApplication(加载初始化器、监听器)
  ↓
2. 启动 Spring 上下文(ConfigurableApplicationContext)
  ↓
   ├─ 环境准备(Environment 加载配置)
   ├─ 上下文初始化(执行初始化器)
   ├─ 刷新上下文(核心:BeanFactory 初始化、Bean 生命周期)
   └─ 启动完成(发布启动事件)
  ↓
3. 运行回调(CommandLineRunner/ApplicationRunner)
  ↓
【应用就绪】

以下所有扩展点都将对应到这个流程的具体节点,先看整体扩展点分布总图:

┌─────────────────────────────────────────────────────────────┐
│                  Spring Boot 扩展点全景                       │
├───────────────────┬─────────────────────────────────────────┤
│ 扩展阶段           │ 核心扩展点                                │
├───────────────────┼─────────────────────────────────────────┤
│ 应用启动初始化      │ ApplicationContextInitializer           │
│                   │ ApplicationListener/ApplicationEvent    │
├───────────────────┼─────────────────────────────────────────┤
│ 配置加载           │ EnvironmentPostProcessor                │
│                   │ PropertySourceLocator                   │
│                   │ @ConfigurationProperties                │
│                   │ PropertyEditor/Converter                │
├───────────────────┼─────────────────────────────────────────┤
│ Bean 生命周期      │ BeanDefinitionRegistryPostProcessor     │
│                   │ BeanFactoryPostProcessor                │
│                   │ BeanPostProcessor                       │
│                   │ InitializingBean/DisposableBean         │
│                   │ @PostConstruct/@PreDestroy              │
├───────────────────┼─────────────────────────────────────────┤
│ 应用启动完成        │ CommandLineRunner/ApplicationRunner     │
├───────────────────┼─────────────────────────────────────────┤
│ Web 专属扩展       │ WebMvcConfigurer/WebFluxConfigurer      │
│                   │ HandlerInterceptor                      │
│                   │ Filter/Interceptor                      │
│                   │ ErrorController                         │
├───────────────────┼─────────────────────────────────────────┤
│ 容器扩展           │ Customizer(如 RestTemplateCustomizer)  │
│                   │ Condition(@Conditional)                │
│                   │ FactoryBean                             │
├───────────────────┼─────────────────────────────────────────┤
│ 应用关闭           │ ApplicationListener<ContextClosedEvent> │
│                   │ DisposableBean/@PreDestroy              │
│                   │ ShutdownHook                            │
└───────────────────┴─────────────────────────────────────────┘

二、分阶段详解扩展点(附图解+示例)

阶段1:应用启动初始化(SpringApplication 初始化)

对应流程:SpringApplication 实例创建 → 上下文初始化前
核心扩展点作用:在上下文初始化前定制环境、上下文配置。

1. ApplicationContextInitializer

  • 定位:Spring 上下文初始化前执行,用于定制 ConfigurableApplicationContext。
  • 触发时机:SpringApplication 初始化后,上下文刷新前。
  • 图解节点
    SpringApplication.run()
      ↓
    创建 ApplicationContext
      ↓
    执行 ApplicationContextInitializer(可多个,按Order排序)
      ↓
    刷新上下文
    
  • 示例
    @Order(1)
    public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            // 定制上下文:比如添加自定义 PropertySource
            ConfigurableEnvironment environment = applicationContext.getEnvironment();
            environment.getPropertySources().addFirst(new MapPropertySource("custom", Map.of("custom.key", "custom.value")));
        }
    }
    // 注册方式1:META-INF/spring.factories
    // org.springframework.context.ApplicationContextInitializer=com.example.CustomApplicationContextInitializer
    // 注册方式2:SpringApplication.addInitializers()
    

2. ApplicationListener(事件监听)

  • 定位:监听 Spring Boot 生命周期事件(如启动、刷新、关闭),实现事件驱动扩展。
  • 核心事件
    事件类型触发时机
    ApplicationStartingEvent应用刚启动,上下文未创建
    ApplicationEnvironmentPreparedEvent环境准备完成
    ApplicationContextInitializedEvent上下文初始化完成
    ApplicationStartedEvent上下文刷新完成,Runner未执行
    ApplicationReadyEvent应用就绪,可处理请求
    ContextClosedEvent应用关闭
  • 图解
    ApplicationStartingEvent → ApplicationEnvironmentPreparedEvent → ApplicationContextInitializedEvent → ApplicationStartedEvent → ApplicationReadyEvent
    
  • 示例
    @Component
    public class CustomApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
        @Override
        public void onApplicationEvent(ApplicationReadyEvent event) {
            // 应用就绪后执行:比如打印启动完成日志、初始化缓存
            System.out.println("应用启动完成,端口:" + event.getApplicationContext().getEnvironment().getProperty("server.port"));
        }
    }
    

阶段2:配置加载扩展(Environment 定制)

对应流程:环境(Environment)初始化 → 配置属性加载
核心扩展点作用:定制配置加载来源、属性转换、配置绑定。

1. EnvironmentPostProcessor

  • 定位:在 Environment 准备完成后,进一步定制环境(比 ApplicationContextInitializer 更早干预配置)。
  • 图解
    SpringApplication.run() → 初始化 Environment → 执行 EnvironmentPostProcessor → 加载 application.yml/properties
    
  • 示例:加载自定义配置文件
    public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
            // 加载自定义配置文件:比如 config/custom.yml
            Resource resource = new ClassPathResource("config/custom.yml");
            if (resource.exists()) {
                try {
                    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
                    PropertySource<?> propertySource = loader.load("customConfig", resource).get(0);
                    environment.getPropertySources().addAfter("applicationConfig: [classpath:/application.yml]", propertySource);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // 注册:META-INF/spring.factories
        // org.springframework.boot.env.EnvironmentPostProcessor=com.example.CustomEnvironmentPostProcessor
    }
    

2. PropertySourceLocator

  • 定位:自定义配置来源(比如从 Nacos/Apollo 加载配置),是 Spring Cloud 配置中心的核心扩展点。
  • 示例
    public class CustomPropertySourceLocator implements PropertySourceLocator {
        @Override
        public PropertySource<?> locate(Environment environment) {
            // 从自定义来源(如数据库)加载配置
            Map<String, Object> configMap = new HashMap<>();
            configMap.put("db.url", "jdbc:mysql://localhost:3306/test");
            return new MapPropertySource("dbConfig", configMap);
        }
    }
    // 注册:通过 EnvironmentPostProcessor 添加
    

3. @ConfigurationProperties + PropertyEditor/Converter

  • 定位:配置属性绑定 + 自定义类型转换(比如 String → 自定义对象)。
  • 示例
    // 配置绑定
    @ConfigurationProperties(prefix = "custom.db")
    @Component
    public class DbProperties {
        private String url;
        private String username;
        // getter/setter
    }
    // 自定义类型转换器
    @Component
    public class StringToDateConverter implements Converter<String, LocalDate> {
        @Override
        public LocalDate convert(String source) {
            return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
    }
    

阶段3:Bean 生命周期扩展(核心)

对应流程:BeanDefinition 注册 → BeanFactory 初始化 → Bean 实例化/初始化/销毁
这是 Spring 最核心的扩展区域,所有 Bean 相关定制都在这里。

核心流程图解(Bean 生命周期):

1. 扫描 BeanDefinition → 注册到 BeanDefinitionRegistry
   ↓
2. 执行 BeanDefinitionRegistryPostProcessor(修改 BeanDefinition)
   ↓
3. 执行 BeanFactoryPostProcessor(定制 BeanFactory)
   ↓
4. Bean 实例化(newInstance)
   ↓
5. 依赖注入(populateBean)
   ↓
6. 执行 BeanPostProcessor.postProcessBeforeInitialization
   ↓
7. Bean 初始化:
   ├─ @PostConstruct
   ├─ InitializingBean.afterPropertiesSet()
   └─ 自定义 init-method
   ↓
8. 执行 BeanPostProcessor.postProcessAfterInitialization
   ↓
9. Bean 就绪使用
   ↓
10. 容器关闭:
    ├─ @PreDestroy
    ├─ DisposableBean.destroy()
    └─ 自定义 destroy-method

关键扩展点详解:

1. BeanDefinitionRegistryPostProcessor
  • 定位:BeanDefinition 注册完成后,可新增/修改/删除 BeanDefinition(优先级高于 BeanFactoryPostProcessor)。
  • 示例:动态注册 Bean
    @Component
    public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            // 动态注册一个 BeanDefinition
            RootBeanDefinition beanDefinition = new RootBeanDefinition(CustomService.class);
            registry.registerBeanDefinition("customService", beanDefinition);
        }
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            // 可选:后续处理 BeanFactory
        }
    }
    
2. BeanFactoryPostProcessor
  • 定位:BeanFactory 初始化完成后,Bean 实例化前,定制 BeanFactory(比如修改 Bean 属性)。
  • 示例
    @Component
    public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            // 修改已注册的 BeanDefinition 属性
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
            beanDefinition.getPropertyValues().add("username", "admin");
        }
    }
    
3. BeanPostProcessor
  • 定位:Bean 实例化后、初始化前后执行,是最常用的扩展点(比如 AOP 代理、属性修改)。
  • 示例
    @Component
    public class CustomBeanPostProcessor implements BeanPostProcessor {
        // 初始化前执行
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof UserService) {
                System.out.println("UserService 初始化前:" + beanName);
            }
            return bean;
        }
        // 初始化后执行(比如生成代理对象)
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof UserService) {
                System.out.println("UserService 初始化后:" + beanName);
            }
            return bean;
        }
    }
    
4. InitializingBean / @PostConstruct / init-method
  • 定位:Bean 初始化阶段执行(优先级:@PostConstruct > InitializingBean > init-method)。
  • 示例
    @Component
    public class UserService implements InitializingBean {
        // 1. @PostConstruct 最先执行
        @PostConstruct
        public void postConstruct() {
            System.out.println("PostConstruct 执行");
        }
        // 2. InitializingBean 其次
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("afterPropertiesSet 执行");
        }
        // 3. init-method 最后(需配置)
        public void initMethod() {
            System.out.println("init-method 执行");
        }
    }
    // 配置 init-method(可选)
    @Bean(initMethod = "initMethod")
    public UserService userService() {
        return new UserService();
    }
    

阶段4:应用启动完成扩展

对应流程:上下文刷新完成 → 应用就绪
核心扩展点:CommandLineRunner / ApplicationRunner(启动后执行任务)。

图解:

ApplicationContext 刷新完成 → 执行 ApplicationRunner(按Order) → 执行 CommandLineRunner(按Order) → ApplicationReadyEvent

示例:

// ApplicationRunner(接收解析后的参数)
@Component
@Order(1)
public class CustomApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner 执行,参数:" + args.getOptionNames());
    }
}

// CommandLineRunner(接收原始命令行参数)
@Component
@Order(2)
public class CustomCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner 执行,参数:" + Arrays.toString(args));
    }
}

阶段5:Web 专属扩展(Spring MVC/WebFlux)

如果是 Web 应用,新增以下扩展点:

1. WebMvcConfigurer(MVC 定制)

  • 定位:定制 Spring MVC 配置(拦截器、视图解析器、消息转换器等)。
  • 示例
    @Configuration
    public class CustomWebMvcConfigurer implements WebMvcConfigurer {
        // 添加拦截器
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new CustomHandlerInterceptor()).addPathPatterns("/**");
        }
        // 定制消息转换器(比如 FastJSON)
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
            converters.add(converter);
        }
    }
    

2. HandlerInterceptor(请求拦截)

  • 定位:拦截 HTTP 请求(预处理、后处理、完成后)。
  • 示例
    public class CustomHandlerInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 请求处理前执行(返回false则拦截)
            System.out.println("preHandle:" + request.getRequestURI());
            return true;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            // 请求处理后,视图渲染前
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // 视图渲染后(无论是否异常)
        }
    }
    

3. ErrorController(全局异常页面/JSON)

  • 定位:定制错误页面/错误 JSON 响应。
  • 示例
    @RestController
    public class CustomErrorController implements ErrorController {
        @RequestMapping("/error")
        public Map<String, Object> handleError(HttpServletRequest request) {
            Map<String, Object> error = new HashMap<>();
            error.put("code", request.getAttribute("javax.servlet.error.status_code"));
            error.put("message", request.getAttribute("javax.servlet.error.message"));
            return error;
        }
        // Spring Boot 2.3+ 推荐用 ErrorAttributes 替代
        @Component
        public static class CustomErrorAttributes extends DefaultErrorAttributes {
            @Override
            public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
                Map<String, Object> attrs = super.getErrorAttributes(webRequest, options);
                attrs.put("custom", "自定义错误信息");
                return attrs;
            }
        }
    }
    

阶段6:其他核心扩展点

1. Customizer 定制器

  • 定位:框架提供的标准化定制接口(比如 RestTemplateCustomizer、Jackson2ObjectMapperBuilderCustomizer)。
  • 示例:定制 RestTemplate
    @Component
    public class CustomRestTemplateCustomizer implements RestTemplateCustomizer {
        @Override
        public void customize(RestTemplate restTemplate) {
            // 添加拦截器、设置超时时间等
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
            restTemplate.getInterceptors().add(new CustomClientHttpRequestInterceptor());
        }
    }
    

2. @Conditional(条件装配)

  • 定位:根据条件动态装配 Bean(比如不同环境加载不同 Bean)。
  • 常用条件注解
    • @ConditionalOnClass:类存在时装配
    • @ConditionalOnMissingClass:类不存在时装配
    • @ConditionalOnBean:Bean 存在时装配
    • @ConditionalOnProperty:配置属性满足时装配
  • 示例
    @Bean
    @ConditionalOnProperty(prefix = "feature", name = "redis.enabled", havingValue = "true")
    public RedisTemplate<String, Object> redisTemplate() {
        return new RedisTemplate<>();
    }
    

3. FactoryBean

  • 定位:定制 Bean 的实例化过程(比如创建复杂对象、代理对象)。
  • 示例
    @Component
    public class CustomFactoryBean implements FactoryBean<CustomObject> {
        // 创建 Bean 实例
        @Override
        public CustomObject getObject() throws Exception {
            CustomObject obj = new CustomObject();
            obj.setId(1);
            obj.setName("FactoryBean 创建");
            return obj;
        }
        // 指定 Bean 类型
        @Override
        public Class<?> getObjectType() {
            return CustomObject.class;
        }
    }
    

阶段7:应用关闭扩展

对应流程:容器关闭 → Bean 销毁
核心扩展点:

  1. ApplicationListener<ContextClosedEvent>:监听容器关闭事件;
  2. DisposableBean / @PreDestroy / destroy-method:Bean 销毁阶段执行;
  3. ShutdownHook:JVM 关闭钩子(Spring Boot 已默认注册,可自定义)。

三、扩展点优先级总结

为了方便记忆,整理核心扩展点的执行优先级(从早到晚):

1. ApplicationStartingEvent(监听器)
2. EnvironmentPostProcessor
3. ApplicationEnvironmentPreparedEvent(监听器)
4. ApplicationContextInitializer
5. ApplicationContextInitializedEvent(监听器)
6. BeanDefinitionRegistryPostProcessor
7. BeanFactoryPostProcessor
8. Bean 实例化 → BeanPostProcessor.postProcessBeforeInitialization
9. @PostConstruct → InitializingBean → init-method
10. BeanPostProcessor.postProcessAfterInitialization
11. ApplicationStartedEvent(监听器)
12. ApplicationRunner → CommandLineRunner
13. ApplicationReadyEvent(监听器)
14. 应用运行中(Web 拦截器/过滤器等)
15. ContextClosedEvent(监听器)→ @PreDestroy → DisposableBean → destroy-method

四、扩展点使用建议

  1. 优先使用框架标准化扩展点:比如 Customizer、WebMvcConfigurer,而非直接修改 BeanFactory;
  2. 利用 @Order 控制执行顺序:多个同类型扩展点通过 @OrderOrdered 接口指定顺序;
  3. 避免过度扩展:优先使用注解(如 @PostConstruct)而非底层扩展点(如 BeanPostProcessor);
  4. 注册方式
    • 轻量级扩展(如监听器、初始化器):通过 META-INF/spring.factories 注册;
    • 业务相关扩展:通过 @Component@Bean 注册。

Comment