SpringMVC + SpringBoot 核心知识点总结

SpringMVC + SpringBoot 核心知识点总结

一、SpringMVC 核心原理

1.1 完整请求执行流程

客户端发起请求后,SpringMVC 遵循固定的核心链路完成请求处理、业务执行、响应返回,完整流程如下:

Plain 复制代码
[User Request] 客户端请求
       │
       ▼
1. DispatcherServlet (前端控制器) ───────> 2. HandlerMapping (处理器映射器)
       │                                         │
       │ <─────── 返回 HandlerExecutionChain 处理器链路 ────┘ (匹配目标 Controller)
       ▼
2. HandlerAdapter (处理器适配器)
       │
       ▼
3. Controller (业务控制器) ───> 执行自定义业务逻辑,返回 ModelAndView / JSON 数据
       │
       ▼
4. ViewResolver (视图解析器) ───────> 5. View (视图渲染) ───────> [User Response] 响应返回客户端

1.2 HandlerAdapter 适配器模式核心原理

1.2.1 设计背景

DispatcherServlet 作为 SpringMVC 的核心调度控制器,负责统一接收所有客户端请求。但 SpringMVC 支持多种类型的处理器(Handler),常见三类:

  • 基于 @Controller + @RequestMapping 的注解式控制器(主流常用)

  • 传统实现 Controller 接口的控制器(老旧方式)

  • 实现 HttpRequestHandler 接口的原生 Servlet 处理器

若 DispatcherServlet 直接调用各类 Handler,需要通过大量if-else 判断类型、强转对象、执行对应方法,代码耦合度极高、扩展性极差。

适配器模式的核心作用 :解耦调度器与具体处理器,DispatcherServlet 只对接统一的适配器接口,由适配器适配、执行不同类型的 Handler,实现统一调用、兼容多端

1.2.2 HandlerAdapter 核心源码接口

所有处理器适配器均实现该接口,定义了「适配判断」和「逻辑执行」两大核心能力:

java 复制代码
public interface HandlerAdapter {

    /**
     * 判断当前适配器是否支持该处理器
     * @param handler 目标处理器
     * @return 支持返回true,否则false
     */
    boolean supports(Object handler);

    /**
     * 适配器核心执行方法:内部调用对应处理器的业务逻辑
     * @return ModelAndView 视图与数据模型
     */
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    
    // 极少使用:获取资源最后修改时间
    long getLastModified(HttpServletRequest request, Object handler);
}

1.2.3 核心调度流程源码

DispatcherServlet 的 doDispatch 方法是请求调度核心,基于适配器模式完成完整调用:

java 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 1. 根据请求路径、参数匹配对应的处理器 Handler
    Object handler = getHandler(request);
    
    // 2. 根据匹配到的 Handler,筛选对应的适配处理器 Adapter
    HandlerAdapter ha = getHandlerAdapter(handler);
    
    // 3. 通过统一适配器接口执行业务逻辑,返回视图模型
    ModelAndView mv = ha.handle(request, response, handler);
    
    // 4. 后续完成视图渲染、响应封装...
}

/**
 * 遍历容器内所有适配器,找到支持当前 Handler 的适配器
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 匹配成功则返回对应适配器
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler + "]");
}

1.2.4 自定义适配器加载机制

DispatcherServlet 初始化时,会自动从 Spring 容器中加载所有 HandlerAdapter 实现类,存入内部 handlerAdapters 列表。

SpringBoot 自动加载规则

  1. 自定义适配器类添加 @Component 注解,注册为 Spring Bean;

  2. 保证类被启动类注解扫描范围覆盖;

  3. SpringBoot 启动初始化 DispatcherServlet 时,执行 initHandlerAdapters 方法,自动扫描容器内所有 HandlerAdapter 类型 Bean。

核心扫描源码逻辑:

java 复制代码
// 从Spring容器中获取所有HandlerAdapter实现类
Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
    this.handlerAdapters = new ArrayList<>(matchingBeans.values());
    // 按照 @Order 注解或 Ordered 接口排序,确定适配器优先级
}

核心结论:只要自定义适配器是 Spring Bean,就会被自动加载至调度器适配器列表,无需手动配置。

二、SpringBoot 核心原理

2.1 自动装配机制(核心)

2.1.1 启动核心注解

SpringBoot 项目启动类的@SpringBootApplication 是组合注解,整合三大核心能力:

  • @SpringBootConfiguration:本质是 @Configuration,标识当前类为全局配置类;

  • @ComponentScan:自动扫描当前包及子包下所有带 @Component、@Service、@RestController 等注解的组件,注入 IOC 容器;

  • @EnableAutoConfiguration自动装配的核心注解,实现按需自动加载框架配置类。

2.1.2 自动装配完整流程

第一步:通过 @Import 导入配置选择器

@EnableAutoConfiguration 底层通过 @Import 引入核心类 AutoConfigurationImportSelector,将其注入 Spring 容器,负责扫描、筛选所有自动配置类。

java 复制代码
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // ...
}
第二步:SPI 机制扫描配置文件

AutoConfigurationImportSelector 的核心方法 selectImports(),基于 Spring 改良的 SPI 机制,扫描全局 Jar 包配置文件:

  • SpringBoot 2.7+/3.x 新版本 :扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件;

  • SpringBoot 2.6 及以下旧版本 :扫描 META-INF/spring.factories 文件。

文件中预定义了大量框架自动配置类全限定类名,示例:

Plain 复制代码
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

启动时会一次性加载数百个预设自动配置类,等待后续筛选。

第三步:@Conditional 条件按需装配

为避免无脑加载所有配置类导致内存浪费、冲突问题,SpringBoot 通过 @Conditional 系列条件注解,实现按需加载、自动适配

以 Redis 自动配置类为例:

java 复制代码
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class) 
// 条件1:项目引入Redis依赖,Classpath存在对应核心类
@EnableConfigurationProperties(RedisProperties.class) 
// 绑定application.properties/application.yml中Redis配置
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate") 
    // 条件2:用户未自定义redisTemplate Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 自动创建默认RedisTemplate并注入容器
        return new RedisTemplate<>();
    }
}
条件装配核心规则
  1. 未引入对应依赖:@ConditionalOnClass 不生效,配置类直接忽略;

  2. 引入依赖但用户自定义 Bean:@ConditionalOnMissingBean 不生效,优先使用用户自定义配置

  3. 引入依赖且无自定义配置:条件全部命中,SpringBoot 自动创建默认 Bean 注入容器。

2.2 SPI 机制(Service Provider Interface)

2.2.1 核心定义

SPI 是 Java 原生提供的动态服务发现、插件化扩展机制 。核心思想:接口定义固定,实现类动态加载

区别于传统编码方式:

  • 普通面向接口编程:编译期绑定实现类,代码写死,改实现需改代码、重编译;

  • SPI 机制:仅定义标准接口,不绑定任何实现,运行时通过约定配置文件,动态扫描、加载外部 Jar 包中的实现类。

2.2.2 核心作用

  • 普通接口解耦:解决项目内部代码的依赖解耦;

  • SPI 动态解耦:解决框架与第三方扩展 Jar 包的解耦,实现插件化扩展。

2.2.3 传统静态接口编程痛点

常规接口调用方式,编译期强制绑定实现类,扩展性极差:

java 复制代码
// 标准接口
public interface Payment { void pay(); }
// 具体实现类
public class WeChatPayment implements Payment {
    @Override
    public void pay() {}
}

// 调用方式:代码写死实现类,耦合严重
Payment pay = new WeChatPayment();
pay.pay();

即使通过 Spring IOC 注入,也仅能解决项目内部依赖管理,框架层面无法预知未来的第三方扩展实现,无法实现插件化加载。

2.2.4 SPI 动态实现方案

框架仅定义接口,不绑定任何实现,运行时通过 ServiceLoader动态扫描加载所有实现类:

java 复制代码
// 框架层:只定义接口,无任何硬编码实现
public interface Payment { void pay(); }

// SPI动态加载逻辑(运行时自动发现所有实现类)
ServiceLoader<Payment> loaders = ServiceLoader.load(Payment.class);
for (Payment payment : loaders) {
    payment.pay(); // 动态执行所有扩展实现
}

核心价值 :让接口具备跨 Jar 包、跨项目、运行期动态组装的能力,是 SpringBoot、Dubbo、JDBC、Logback 等主流框架核心扩展机制。

相关推荐
亦暖筑序12 分钟前
Java 8老系统Browser Agent实战:三层拦截把AI操作后台变成可审计流程
java·后端·设计模式
用户342323237631719 分钟前
GPIO控制与按键中断入门
后端
Gopher_HBo20 分钟前
Go语言学习笔记(十五)Http响应
后端
kfaino1 小时前
码农的AI翻身(六)你好,我叫 Parameter
后端·aigc
掘金者阿豪1 小时前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
猪猪拆迁队2 小时前
虚拟工厂仿真引擎的架构设计:让一条产线可编程、可观测、可干预
后端·ai编程
字节跳动数据库3 小时前
文章分享——相似函数处理方法
人工智能·后端·程序员
云技纵横3 小时前
@Transactional 失效的 7 种场景:第 5 种最难排查
后端
用户6757049885023 小时前
你知道 Go 结构体和结构体指针调用的区别吗?一文带你彻底搞懂!
后端·go
程序员cxuan3 小时前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构