题目
Spring MVC请求处理流程解析与拦截器应用
信息
- 类型:问答
- 难度:⭐⭐
考点
Spring MVC请求生命周期, 拦截器实现原理, 线程安全实践, 异常处理机制
快速回答
Spring MVC请求处理的核心流程分为六个阶段:
- 请求首先到达DispatcherServlet(前端控制器)
- DispatcherServlet 委托 HandlerMapping 查找处理器
- 通过 HandlerAdapter 执行控制器方法
- 控制器返回ModelAndView(或响应体)
- ViewResolver 解析视图名称
- 视图渲染并返回响应
拦截器应用要点:
- 实现
HandlerInterceptor接口的三个方法 - 通过
@ControllerAdvice实现全局异常处理 - 控制器需保持无状态确保线程安全
一、Spring MVC 核心工作流程
完整请求处理流程:
- DispatcherServlet 接收请求:作为前端控制器,是所有请求的入口
- HandlerMapping 路由匹配:根据URL找到对应的Controller和方法
@Controller @RequestMapping("/users") public class UserController { @GetMapping("/{id}") public String getUser(@PathVariable Long id) { ... } } - HandlerAdapter 执行控制器:适配不同处理器类型(如@Controller注解类)
- 拦截器预处理:执行
preHandle()方法(认证/日志等) - 参数绑定与方法执行:自动处理参数转换和验证
@PostMapping public ResponseEntity<User> createUser(@Valid @RequestBody UserDto dto) { // 业务逻辑 } - 拦截器后处理:执行
postHandle()(模型修改等) - ViewResolver 解析视图:将逻辑视图名映射到具体视图技术(JSP/Thymeleaf等)
- 渲染视图:结合模型数据生成响应
- 拦截器最终处理:执行
afterCompletion()(资源清理等)
二、拦截器实现与最佳实践
自定义拦截器示例:
public class AuditInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 1. 前置处理:记录请求开始时间
request.setAttribute("startTime", System.currentTimeMillis());
return true; // 继续流程
}
@Override
public void postHandle(/* 参数省略 */) {
// 2. 后置处理:可修改ModelAndView
}
@Override
public void afterCompletion(/* 参数省略 */) {
// 3. 完成处理:计算请求耗时
long duration = System.currentTimeMillis() - (Long)request.getAttribute("startTime");
log.info("请求耗时:{}ms", duration);
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuditInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/static/**");
}
}线程安全实践:
- 控制器中避免使用实例变量(应使用局部变量或ThreadLocal)
- 拦截器需设计为无状态,若需存储请求级数据使用request属性
三、常见错误与解决方案
| 错误类型 | 现象 | 解决方案 |
|---|---|---|
| 拦截器阻塞 | preHandle返回false后流程中断 | 确保在拦截器中正确发送错误响应 |
| 视图解析失败 | 返回视图名但未配置ViewResolver | 检查是否添加了如Thymeleaf等视图引擎依赖 |
| 参数绑定异常 | 400错误(如日期格式不匹配) | 使用@DateTimeFormat或自定义Converter |
四、扩展知识
- 全局异常处理:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(...); } } - 异步请求处理:使用
@Async或返回Callable/DeferredResult - RESTful优化:结合
@RestController和ResponseEntity构建API
五、流程优化建议
- 使用拦截器链处理横切关注点(如认证、日志)而非在控制器重复编码
- 对于API开发可直接返回数据对象(配合
@ResponseBody)跳过视图解析 - 利用
HandlerMethodArgumentResolver自定义参数解析器