Spring MVC请求处理流程
约 1401 字大约 5 分钟
spring-mvcweb
2025-03-26
概述
Spring MVC 是 Spring 框架中用于构建 Web 应用的核心模块,基于经典的 MVC(Model-View-Controller)架构模式。其核心组件 DispatcherServlet 作为前端控制器,负责统一调度请求的处理流程。本文深入分析从 HTTP 请求到达到响应返回的完整链路。
请求处理总体流程
核心组件详解
1. DispatcherServlet —— 前端控制器
DispatcherServlet 继承自 HttpServlet,是整个 Spring MVC 的入口。它在初始化时加载各种策略组件:
2. HandlerMapping —— 请求映射
HandlerMapping 负责将 HTTP 请求映射到对应的 Handler(Controller 方法)。Spring MVC 提供了多种实现:
| 实现类 | 说明 |
|---|---|
RequestMappingHandlerMapping | 处理 @RequestMapping 注解 |
SimpleUrlHandlerMapping | 基于 URL 路径映射 |
BeanNameUrlHandlerMapping | 基于 Bean 名称映射 |
RouterFunctionMapping | 处理函数式端点 |
// @RequestMapping 是最常用的映射方式
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User createUser(@RequestBody @Valid UserRequest request) {
return userService.create(request);
}
@GetMapping
public Page<User> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String keyword) {
return userService.search(keyword, PageRequest.of(page, size));
}
}3. HandlerAdapter —— 处理器适配器
HandlerAdapter 负责调用具体的 Handler 方法。RequestMappingHandlerAdapter 是最核心的实现,负责处理 @RequestMapping 标注的方法:
4. 参数解析器(HandlerMethodArgumentResolver)
Spring MVC 提供了丰富的参数解析器,自动将请求数据绑定到方法参数:
@RestController
public class DemoController {
// @PathVariable - 从URL路径中提取
@GetMapping("/orders/{orderId}/items/{itemId}")
public OrderItem getItem(@PathVariable String orderId,
@PathVariable Long itemId) {
return orderService.getItem(orderId, itemId);
}
// @RequestBody - 从请求体解析JSON
@PostMapping("/orders")
public Order createOrder(@RequestBody @Valid CreateOrderRequest request) {
return orderService.create(request);
}
// @RequestParam - 从查询参数获取
@GetMapping("/search")
public List<Product> search(
@RequestParam String keyword,
@RequestParam(defaultValue = "price") String sortBy) {
return productService.search(keyword, sortBy);
}
// HttpServletRequest, HttpServletResponse - 直接注入
@GetMapping("/download")
public void download(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 直接操作原始请求和响应
}
// 自定义参数解析
@GetMapping("/profile")
public UserProfile getProfile(@CurrentUser User user) {
return profileService.getProfile(user.getId());
}
}自定义参数解析器:
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CurrentUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
String token = request.getHeader("Authorization");
return tokenService.parseUser(token);
}
}
// 注册自定义解析器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CurrentUserArgumentResolver());
}
}5. 返回值处理器(HandlerMethodReturnValueHandler)
// @ResponseBody + 对象 → JSON(通过 HttpMessageConverter)
@GetMapping("/api/user/{id}")
@ResponseBody
public User getUser(@PathVariable Long id) {
return userService.findById(id); // 自动序列化为JSON
}
// ResponseEntity - 完整控制HTTP响应
@GetMapping("/api/file/{name}")
public ResponseEntity<Resource> downloadFile(@PathVariable String name) {
Resource resource = storageService.load(name);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + name + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
// ModelAndView - 传统视图渲染
@GetMapping("/users")
public ModelAndView listUsers() {
ModelAndView mav = new ModelAndView("user/list");
mav.addObject("users", userService.findAll());
return mav;
}拦截器(HandlerInterceptor)
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// Controller方法执行之前
String token = request.getHeader("Authorization");
if (token == null || !tokenService.validate(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false; // 中断请求链
}
request.setAttribute("currentUser", tokenService.parseUser(token));
return true; // 继续执行
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// Controller方法执行之后,视图渲染之前
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 请求完成之后(无论是否异常)
// 适合做资源清理
}
}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthenticationInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/login", "/api/public/**");
}
}异常处理
// 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
return new ErrorResponse("NOT_FOUND", ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.toList();
return new ErrorResponse("VALIDATION_FAILED", String.join(", ", errors));
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGeneral(Exception ex) {
log.error("Unhandled exception", ex);
return new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred");
}
}doDispatch 核心源码分析
// DispatcherServlet.doDispatch 简化版
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
try {
// 1. 检查是否多部分请求(文件上传)
processedRequest = checkMultipart(request);
// 2. 查找Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3. 查找HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 4. 执行拦截器 preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 5. 调用Handler(Controller方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 6. 执行拦截器 postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
// 异常处理
mv = processHandlerException(request, response, mappedHandler, ex);
}
// 7. 渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, null);
}总结
Spring MVC 的请求处理流程以 DispatcherServlet 为核心,通过 HandlerMapping 定位处理器、HandlerAdapter 适配执行、ViewResolver 解析视图,形成了一套高度可扩展的处理链。拦截器、参数解析器、返回值处理器和异常处理器提供了丰富的扩展点,使开发者可以灵活定制请求处理逻辑。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于