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 自动加载规则:
-
自定义适配器类添加
@Component注解,注册为 Spring Bean; -
保证类被启动类注解扫描范围覆盖;
-
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<>();
}
}
条件装配核心规则
-
未引入对应依赖:
@ConditionalOnClass不生效,配置类直接忽略; -
引入依赖但用户自定义 Bean:
@ConditionalOnMissingBean不生效,优先使用用户自定义配置; -
引入依赖且无自定义配置:条件全部命中,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 等主流框架核心扩展机制。