Lesson 58 · Spring 生态核心原理
Spring MVC 请求处理全流程:DispatcherServlet 到 View
面试官:一次 HTTP 请求在 Spring 内部经历了哪些组件?
Spring MVC 的核心设计模式是 前端控制器(Front Controller),所有请求统一由 DispatcherServlet 接收,再分发给各个组件处理。
DispatcherServlet 继承自 HttpServlet,是整个 Spring MVC 的入口。它的核心方法是 doDispatch(),负责协调所有组件:
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
Exception dispatchException = null;
try {
// ① 通过 HandlerMapping 找到处理器
mappedHandler = getHandler(request);
// ② 通过 HandlerAdapter 调用处理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ③ 执行拦截器 preHandle
if (!mappedHandler.applyPreHandle(request, response)) { return; }
// ④ 真正调用 Controller 方法
mv = ha.handle(request, response, mappedHandler.getHandler());
// ⑤ 执行拦截器 postHandle
mappedHandler.applyPostHandle(request, response, mv);
} catch (Exception ex) {
dispatchException = ex;
}
// ⑥ 处理结果(渲染视图 / 写 JSON / 处理异常)
processDispatchResult(request, response, mappedHandler, mv, dispatchException);
}
HandlerMapping:URL 到处理器的映射
HandlerMapping 的职责是根据请求 URL 找到对应的处理器(Handler),并组装成 HandlerExecutionChain(包含处理器 + 拦截器链)。
| 实现类 | 映射方式 | 使用场景 |
|---|---|---|
RequestMappingHandlerMapping | @RequestMapping 注解 | 最常用,注解驱动 |
BeanNameUrlHandlerMapping | Bean 名称以 "/" 开头 | XML 配置时代遗留 |
SimpleUrlHandlerMapping | 显式配置 URL 映射 | 简单静态映射 |
// Spring 启动时扫描所有 @Controller / @RestController
// 解析 @RequestMapping,注册到内部映射表:
// 映射表结构(简化)
Map<RequestMappingInfo, HandlerMethod>
// RequestMappingInfo 包含:
// - URL patterns: ["/api/users/{id}"]
// - HTTP methods: [GET]
// - headers: ["Accept=application/json"]
// - params: ["type=admin"]
// - consumes: ["application/json"]
// - produces: ["application/json"]
// HandlerMethod 包含:
// - bean: UserController 实例
// - method: getUserById() 方法对象
查找过程的返回值是 HandlerExecutionChain,它不仅包含 Handler 本身,还包含匹配到的拦截器:
public class HandlerExecutionChain {
private final Object handler; // 处理器(HandlerMethod)
private HandlerInterceptor[] interceptors; // 匹配的拦截器数组
}
HandlerAdapter:统一调用不同 Handler
| HandlerAdapter | 适配的 Handler 类型 | 说明 |
|---|---|---|
RequestMappingHandlerAdapter | HandlerMethod | 处理 @RequestMapping 注解方法(最常用) |
HttpRequestHandlerAdapter | HttpRequestHandler | 处理静态资源等低级请求 |
SimpleControllerHandlerAdapter | Controller 接口 | 老式 Controller 接口实现 |
RequestMappingHandlerAdapter 是日常使用最多的适配器,它的 handle() 方法内部做了大量工作:
protected ModelAndView handleInternal(...) {
// ① 解析方法参数
// @RequestParam → 从 query string / form 取值
// @PathVariable → 从 URL 模板变量取值
// @RequestBody → 用 HttpMessageConverter 反序列化
// @RequestHeader → 从请求头取值
// ② 反射调用 Controller 方法
Object returnValue = method.invoke(bean, args);
// ③ 处理返回值
// @ResponseBody → 用 HttpMessageConverter 序列化为 JSON
// String → 当作视图名交给 ViewResolver
// ModelAndView → 包含模型数据和视图名
}
参数解析器和返回值处理器各自维护一个列表,Spring 按顺序匹配第一个支持当前参数/返回类型的处理器:
// 常见的参数解析器(按优先级排列)
1. RequestParamMethodArgumentResolver // @RequestParam
2. PathVariableMethodArgumentResolver // @PathVariable
3. RequestResponseBodyMethodProcessor // @RequestBody(兼做返回值)
4. RequestHeaderMethodArgumentResolver // @RequestHeader
5. ServletRequestMethodArgumentResolver // HttpServletRequest
6. ModelAttributeMethodProcessor // @ModelAttribute
Controller 处理与 REST 响应(@ResponseBody)
在现代 REST API 开发中,Controller 方法通常标注 @ResponseBody(或类级别 @RestController),返回值直接写入 HTTP 响应体,不经过视图解析。
@RestController // = @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user);
}
}
@ResponseBody 的序列化流程由 HttpMessageConverter 完成:
ViewResolver:传统视图解析(非 REST 场景)
如果 Controller 返回一个视图名(String 类型,没有 @ResponseBody),Spring 会通过 ViewResolver 将其解析为具体的 View 对象:
@Controller // 注意:不是 @RestController
public class PageController {
@GetMapping("/dashboard")
public String dashboard(Model model) {
model.addAttribute("user", currentUser);
return "dashboard"; // 返回视图名
}
}
// ViewResolver 解析过程:
// "dashboard" → InternalResourceViewResolver
// → prefix + "dashboard" + suffix
// → "/WEB-INF/views/dashboard.html"
// → 渲染 HTML 写入响应体
| ViewResolver | 视图技术 | 说明 |
|---|---|---|
InternalResourceViewResolver | JSP | 前缀 + 视图名 + 后缀 |
ThymeleafViewResolver | Thymeleaf | Spring Boot 推荐模板 |
FreeMarkerViewResolver | FreeMarker | 老牌模板引擎 |
ContentNegotiatingViewResolver | 多格式 | 根据 Accept 头选择视图 |
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
cache: false # 开发时关闭缓存
异常处理与拦截器
Spring MVC 提供了多层异常处理机制:
// 优先级 1:Controller 内的 @ExceptionHandler
@RestController
public class UserController {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity.status(404).body(ex.getMessage());
}
}
// 优先级 2:@ControllerAdvice 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return ResponseEntity.status(500).body(new ErrorResponse(ex));
}
}
// 优先级 3:HandlerExceptionResolver(框架级别)
// - DefaultHandlerExceptionResolver → 处理 Spring 内部异常
// - ResponseStatusExceptionResolver → 处理 @ResponseStatus
拦截器(HandlerInterceptor)在请求处理的前后执行,形成"洋葱模型":
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req,
HttpServletResponse res,
Object handler) {
// Controller 方法执行前调用
// 返回 false → 终止请求,不再往下执行
// 返回 true → 继续执行下一个拦截器或 Handler
log.info("Request: {} {}", req.getMethod(), req.getRequestURI());
return true;
}
@Override
public void postHandle(HttpServletRequest req,
HttpServletResponse res,
Object handler, ModelAndView mv) {
// Controller 方法执行后、视图渲染前调用
// 注意:@ResponseBody 场景下 mv 为 null
}
@Override
public void afterCompletion(HttpServletRequest req,
HttpServletResponse res,
Object handler, Exception ex) {
// 请求完成后调用(包括异常情况)
// 适合做资源清理、日志记录
}
}
- 总入口:DispatcherServlet.doDispatch() 是所有请求的调度中心
- 查找处理器:HandlerMapping 根据 URL 匹配 HandlerMethod,返回 HandlerExecutionChain(含拦截器)
- 调用处理器:HandlerAdapter 适配不同类型的 Handler,解析参数、反射调用、处理返回值
- REST 响应:@ResponseBody 通过 HttpMessageConverter 将返回值序列化写入响应体,不走 ViewResolver
- 异常处理:@ExceptionHandler(局部)→ @ControllerAdvice(全局)→ HandlerExceptionResolver(框架)
- 拦截器:HandlerInterceptor 的 preHandle / postHandle / afterCompletion 形成洋葱模型