SpringBoot手动配置:WebMvcConfigurer接口实现类的生效原理

正文内容

前言

在 Spring Boot 开发中,我们经常需要自定义 Web 配置,比如添加拦截器、配置跨域或静态资源映射。我们通常熟知的"标准姿势"是这样的:

java 复制代码
@Configuration
public class MyWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加一个拦截器
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

写完这段代码,Spring Boot 启动后,我们的拦截器就神奇地生效了。但你有没有想过:为什么?

  • 是谁在调用这个 addInterceptors 方法?
  • 为什么加上 @Configuration 它就被发现了?
  • 如果有多个类都实现了这个接口,Spring 是怎么处理的?

今天我们就来扒一扒这背后的底层原理。


一、 核心三步曲

整个生效流程可以概括为三个核心步骤:Bean 的注册 -> Bean 的搜集 -> Bean 的执行

这背后运用了 Spring 容器的 集合注入(Collection Injection) 特性和 委派模式(Delegation Pattern)

1. 入场券:@Configuration

首先,我们在类上加了 @Configuration 注解。

这意味着该类被 Spring 扫描到后,会被实例化并注册到 IOC 容器中,成为一个 Bean

此时,你的 MyWebConfig 对象安静地躺在 Spring 容器里。它的身份有两个:

  1. 它是一个 Bean。
  2. 它的类型是 WebMvcConfigurer

画外音 :如果没有 @Configuration(或 @Component),Spring 容器根本不知道这个类的存在,后续的一切都不会发生。

2. 搜集员:DelegatingWebMvcConfiguration

在 Spring MVC 的自动化配置体系中,有一个核心配置类叫 DelegatingWebMvcConfiguration。它是 Spring MVC 能够识别用户自定义配置的"总管家"。

让我们看看它的源码(关键部分):

java 复制代码
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    // 1. 定义一个"复合对象",用来存放所有的配置类
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

    // 2. 【核心魔法】利用 Spring 的自动注入特性
    // Spring 会自动去容器里查找 *所有* 类型为 WebMvcConfigurer 的 Bean
    // 并把它们打包成一个 List 注入进来
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            // 将搜集到的所有配置类(包括你写的 MyWebConfig),添加到复合对象中
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
    
    // ...
}

原理解析:

Spring 的依赖注入非常强大。当你对 List<Interface> 类型使用 @Autowired 时,Spring 不会报错,而是会地毯式搜索容器,把所有实现了该接口的 Bean 全部找出来,放入 List 中。

结果: 你写的 MyWebConfig 就这样被"搜集"到了总管家手中。

3. 执行者:委派模式

当 Spring Boot 启动,准备初始化拦截器(Interceptors)时,会调用 DelegatingWebMvcConfiguration 中的 addInterceptors 方法。

但这个"总管家"自己并不干活,它把任务委派 给了那个"复合对象" (WebMvcConfigurerComposite)。

java 复制代码
// DelegatingWebMvcConfiguration.java

@Override
protected void addInterceptors(InterceptorRegistry registry) {
    // 总管家说:我不知道要加什么拦截器,问问那帮配置类吧
    this.configurers.addInterceptors(registry);
}

紧接着,复合对象会遍历之前搜集到的所有配置类:

java 复制代码
// WebMvcConfigurerComposite.java

@Override
public void addInterceptors(InterceptorRegistry registry) {
    // 遍历 List,依次调用每一个配置类的 addInterceptors 方法
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.addInterceptors(registry);
    }
}

结果: 循环执行中,你重写的 MyWebConfig.addInterceptors() 方法就被调用了!你的拦截器也就成功注册到了 registry 中。


二、 深入:是谁触发了这一切?

你可能会追问:"那又是谁调用了 DelegatingWebMvcConfigurationaddInterceptors 呢?"

这就涉及到了 模板方法模式

DelegatingWebMvcConfiguration 继承自父类 WebMvcConfigurationSupport。这个父类负责创建 Spring MVC 的核心组件。

静态资源映射 为例,父类中有一个 @Bean 方法:

java 复制代码
// WebMvcConfigurationSupport.java

@Bean
public HandlerMapping resourceHandlerMapping(...) {
    // 1. 创建注册表
    ResourceHandlerRegistry registry = new ResourceHandlerRegistry(...);
    
    // 2. 【调用点】调用 addResourceHandlers
    // 虽然这里是在父类写的,但因为子类(Delegating...)重写了它,
    // 根据 Java 多态性,实际执行的是子类的逻辑(即去调用所有用户的配置)
    addResourceHandlers(registry); 
    
    // 3. 返回创建好的 Mapping
    return registry.getHandlerMapping();
}

完整链路闭环:

  1. Spring 启动,准备创建 HandlerMapping Bean。
  2. 执行父类的 @Bean 方法。
  3. 父类方法内部调用 addResourceHandlers(钩子方法)。
  4. 子类 DelegatingWebMvcConfiguration 响应调用。
  5. 子类委派给 Composite 复合对象。
  6. 复合对象遍历 List,最终调用你写的代码
相关推荐
甜鲸鱼5 分钟前
【Spring AOP】操作日志的完整实现与原理剖析
java·spring boot·spring
狗头大军之江苏分军9 分钟前
年底科技大考:2025 中国前端工程师的 AI 辅助工具实战盘点
java·前端·后端
一 乐37 分钟前
酒店客房预订|基于springboot + vue酒店客房预订系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
计算机毕设指导638 分钟前
基于Spring Boot的防诈骗管理系统【源码文末联系】
java·spring boot·后端·spring·tomcat·maven·intellij-idea
开心就好202542 分钟前
IOScer 开发环境证书包括哪些,证书、描述文件与 App ID 的协同管理实践
后端
a程序小傲1 小时前
饿了吗Java面试被问:Redis的持久化策略对比(RDBVS AOF)
java·redis·面试
码事漫谈1 小时前
终于找到我想要的远程工具了!
后端
我家领养了个白胖胖1 小时前
MCP模型上下文协议 Model Context Protocol & 百度地图MCP开发
java·后端·ai编程
Coder_Boy_1 小时前
基于DDD+Spring Boot 3.2+LangChain4j构建企业级智能客服系统
java·人工智能·spring boot·后端
开心猴爷1 小时前
苹果商店 App 上架要求,探讨如何通过系统审核
后端