1. Spring MVC 架构概述
Spring MVC 是 Spring Framework 提供的 Web 框架实现,基于经典的 Model-View-Controller 设计模式。作为 Java EE 领域最成熟的 Web 框架之一,它通过清晰的组件分工和灵活的扩展机制,为开发者提供了构建企业级 Web 应用的完整解决方案。
在实际项目中,Spring MVC 的工作流程可以类比为餐厅的用餐体验:DispatcherServlet 如同餐厅经理,HandlerMapping 是领位员,Controller 则是厨师,ViewResolver 负责摆盘,而各种 HandlerAdapter 就是厨房里的烹饪工具。这种分工协作的模式使得每个组件都能专注于自己的职责范围。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心组件详解
2.1 DispatcherServlet:前端控制器
作为整个流程的中枢神经,DispatcherServlet 本质上是一个 Servlet 实现。它在 web.xml 中的配置通常如下:
xml复制<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
关键特性:
- 继承自 HttpServlet,是唯一的请求入口点
- 默认加载/WEB-INF/[servlet-name]-servlet.xml 配置文件
- 通过 load-on-startup 参数控制初始化时机
- 支持 RESTful 风格的 URL 模式匹配
实际开发中建议将静态资源排除在 DispatcherServlet 映射之外,可通过
<mvc:resources>配置或交由 Web 服务器直接处理。
2.2 HandlerMapping:请求路由
HandlerMapping 组件负责建立请求 URL 与处理器之间的映射关系。Spring MVC 提供了多种实现:
| 实现类 | 描述 | 适用场景 |
|---|---|---|
| BeanNameUrlHandlerMapping | 根据 Bean 名称匹配URL | 简单应用 |
| SimpleUrlHandlerMapping | 显式配置URL映射 | 传统Web应用 |
| RequestMappingHandlerMapping | 基于注解配置 | 现代REST应用 |
| RouterFunctionMapping | 函数式编程风格 | 响应式应用 |
现代项目通常采用注解驱动方式:
java复制@Controller
@RequestMapping("/orders")
public class OrderController {
@GetMapping("/{id}")
public String getOrder(@PathVariable Long id) {
// ...
}
}
2.3 HandlerAdapter:处理器适配
不同的处理器需要不同的调用方式,HandlerAdapter 的设计采用了适配器模式:
- SimpleControllerHandlerAdapter:适配传统 Controller 接口
- HttpRequestHandlerAdapter:适配 HttpRequestHandler 接口
- RequestMappingHandlerAdapter:处理 @RequestMapping 注解方法
- HandlerFunctionAdapter:支持函数式端点
RequestMappingHandlerAdapter 的工作流程尤其值得关注:
- 解析方法参数(@RequestParam、@RequestBody 等)
- 执行方法调用
- 处理返回值(ModelAndView、@ResponseBody 等)
- 处理异常(@ExceptionHandler)
2.4 ViewResolver:视图解析
视图解析器将逻辑视图名转换为实际视图实现:
java复制public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
常用实现包括:
- InternalResourceViewResolver:JSP 视图
- ThymeleafViewResolver:Thymeleaf 模板
- FreeMarkerViewResolver:FreeMarker 模板
- ContentNegotiatingViewResolver:根据内容协商选择视图
配置示例:
xml复制<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
2.5 HandlerExceptionResolver:异常处理
异常解析器提供了统一的错误处理机制:
java复制public interface HandlerExceptionResolver {
ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);
}
实际开发中更常用的是 @ControllerAdvice 注解:
java复制@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> handleResourceNotFound(ResourceNotFoundException ex) {
ErrorDetail error = new ErrorDetail("Not Found", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
}
3. 请求处理全流程解析
3.1 请求到达阶段
- 容器初始化:Tomcat/Jetty 等 Servlet 容器加载 web.xml
- ContextLoaderListener 创建根应用上下文(父容器)
- DispatcherServlet 初始化自身应用上下文(子容器)
- 组件初始化:HandlerMapping、HandlerAdapter 等 Bean 被实例化
3.2 请求处理阶段
完整处理流程如下:
- 请求接收:DispatcherServlet 的 service() 方法被调用
- 查找处理器:
java复制mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } - 获取适配器:
java复制HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); - 拦截器预处理:
java复制if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } - 实际处理:
java复制
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); - 视图渲染:
java复制
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
3.3 响应生成阶段
视图渲染的关键步骤:
- 解析视图名称
- 处理模型数据
- 调用视图的 render() 方法
- 写入响应输出流
对于 RESTful 接口,通常使用 @ResponseBody 跳过视图解析:
java复制@GetMapping("/api/users")
@ResponseBody
public List<User> listUsers() {
return userService.findAll();
}
4. 高级特性与最佳实践
4.1 异步处理支持
Spring MVC 提供了完善的异步处理机制:
java复制@GetMapping("/async")
public Callable<String> asyncProcessing() {
return () -> {
Thread.sleep(2000); // 模拟耗时操作
return "async-result";
};
}
底层原理:
- 请求线程被释放回容器线程池
- 业务逻辑在单独线程中执行
- 完成后重新派发请求获取结果
4.2 拦截器应用
自定义拦截器示例:
java复制public class AuditInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
log.info("Request started: {}", request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
log.info("Request completed: {}", request.getRequestURI());
}
}
配置方式:
xml复制<mvc:interceptors>
<bean class="com.example.AuditInterceptor"/>
</mvc:interceptors>
4.3 性能优化建议
- 合理配置 HandlerMapping 顺序
- 使用缓存视图解析器
- 优化模型数据处理
- 合理使用静态资源处理
- 异步处理耗时操作
5. 常见问题排查
5.1 404 错误排查
- 检查 DispatcherServlet 的 URL 映射
- 确认 HandlerMapping 配置正确
- 验证 Controller 的 @RequestMapping 路径
- 查看是否被拦截器阻断
5.2 参数绑定问题
常见解决方案:
- 检查参数名称是否匹配
- 验证类型转换器配置
- 使用 @RequestParam 明确指定
- 自定义 PropertyEditor 或 Converter
5.3 视图解析失败
典型原因:
- 视图名称拼写错误
- ViewResolver 配置不正确
- 模板文件位置错误
- 缺少必要的视图技术依赖
在开发复杂Web应用时,理解Spring MVC的内部工作机制能帮助开发者更高效地解决问题。建议通过调试模式逐步跟踪请求处理流程,这对深入掌握框架行为非常有帮助。对于现代应用开发,可以结合Spring Boot的自动配置来简化大部分样板配置。
