SpringMVC拦截器与异常处理原理深度解析
目录
- 引言
- HandlerInterceptor拦截器体系
- 拦截器执行链完整解析
- 拦截器注册与配置
- 异常处理体系全景
- HandlerExceptionResolver执行链
- @ExceptionHandler深度解析
- @ControllerAdvice全局异常处理
- 异常处理流程时序
- 拦截器与异常处理协同
- 实战:完整登录认证方案
- 总结
引言
SpringMVC的拦截器(Interceptor)和异常处理(Exception Handler)是Web层的两大核心扩展机制。拦截器负责请求的前置/后置/完成处理,异常处理负责将各类异常转换为统一的响应格式。理解这两套机制的底层原理,是掌握SpringMVC高级特性的必经之路。
本文深入剖析:
HandlerInterceptor三方法的执行时机与数据共享
HandlerExecutionChain的完整执行流程
HandlerExceptionResolver异常处理链
@ExceptionHandler方法解析与优先级
@ControllerAdvice的扫描与注册机制
- 拦截器与异常处理的协同工作模式
1. HandlerInterceptor拦截器体系
1.1 接口完整定义
public interface HandlerInterceptor {
default boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true;
}
default void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex) throws Exception {
}
}
1.2 接口类图
1.3 执行时序图
1.4 执行顺序核心规则
2. 拦截器执行链完整解析
2.1 HandlerExecutionChain源码解析
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private final List<HandlerInterceptor> interceptorList = new ArrayList<>(4);
private int interceptorIndex = -1;
boolean applyPreHandle(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (interceptors == null) {
return true;
}
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
void applyPostHandle(HttpServletRequest request,
HttpServletResponse response,
ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (interceptors == null) {
return;
}
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response,
@Nullable Exception ex) {
HandlerInterceptor[] interceptors = getInterceptors();
if (interceptors == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response,
int interceptorIndex,
@Nullable Exception ex) {
HandlerInterceptor[] interceptors = getInterceptors();
if (interceptors == null) {
return;
}
for (int i = interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
2.2 preHandle返回false的影响
2.3 异常时的afterCompletion
2.4 请求属性数据共享
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
User user = authService.validateToken(request);
request.setAttribute("currentUser", user);
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView mv) throws Exception {
User user = (User) request.getAttribute("currentUser");
if (mv != null && user != null) {
mv.addObject("operator", user.getName());
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
long duration = System.currentTimeMillis() - (Long) request.getAttribute("startTime");
logService.recordAccess(request.getRequestURI(), duration, ex);
UserContext.remove();
}
}
3. 拦截器注册与配置
3.1 WebMvcConfigurer扩展点
3.2 InterceptorRegistry详解
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList<>();
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
registrations.add(registration);
return registration;
}
public List<InterceptorRegistration> getRegistrations() {
return Collections.unmodifiableList(this.registrations);
}
}
3.3 拦截器注册流程
3.4 路径匹配规则
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login", "/api/register", "/api/public/**")
.excludePathPatterns("/error")
.order(1);
}
}
| 模式 |
匹配示例 |
/api/** |
/api, /api/users, /api/users/123 |
/api/users/* |
/api/users/123 (单层级) |
/*.html |
/index.html |
/**/*.png |
/images/logo.png |
4. 异常处理体系全景
4.1 异常处理架构图
4.2 HandlerExceptionResolver接口
4.3 异常处理流程决策
5. HandlerExceptionResolver执行链
5.1 DispatcherServlet异常处理入口
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) {
HandlerExecutionChain mappedHandler = null;
Exception dispatchException = null;
try {
mappedHandler = getHandler(request);
if (!mappedHandler.applyPreHandle(request, response)) {
return;
}
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
mappedHandler.applyPostHandle(request, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException(
"Handler dispatch failed", err);
}
processDispatchResult(request, response, mappedHandler, mv, dispatchException);
}
private void processDispatchResult(HttpServletRequest request,
HttpServletResponse response,
HandlerExecutionChain mappedHandler,
@Nullable ModelAndView mv,
@Nullable Exception exception) {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception)
.getModelAndView();
errorView = true;
} else {
HandlerExceptionResolver[] resolvers = getHandlerExceptionResolvers();
for (HandlerExceptionResolver resolver : resolvers) {
mv = resolver.resolveException(
request, response, mappedHandler.getHandler(), exception);
if (mv != null) {
errorView = true;
break;
}
}
}
}
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
5.2 HandlerExceptionResolverComposite执行时序
5.3 SimpleMappingExceptionResolver使用
@Configuration
public class ExceptionConfig {
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("BusinessException", "error/business");
mappings.setProperty("ValidationException", "error/validation");
mappings.setProperty("Exception", "error/general");
resolver.setExceptionMappings(mappings);
resolver.setDefaultErrorView("error/default");
resolver.setExceptionAttribute("exception");
return resolver;
}
}
5.4 DefaultHandlerExceptionResolver支持的异常
| 异常类型 |
HTTP状态码 |
NoHandlerFoundException |
404 |
HttpRequestMethodNotSupportedException |
405 |
MissingServletRequestParameterException |
400 |
TypeMismatchException |
400 |
HttpMessageNotReadableException |
400 |
HttpMediaTypeNotSupportedException |
415 |
6. @ExceptionHandler深度解析
6.1 @ExceptionHandler注解定义
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
Class~? extends Throwable~[] value() default {};
}
6.2 @ExceptionHandler方法签名
6.3 支持的方法参数
6.4 异常匹配优先级
| 优先级 |
匹配方式 |
示例 |
| 1 |
精确匹配 |
@ExceptionHandler(BusinessException.class) |
| 2 |
祖先类匹配 |
@ExceptionHandler(RuntimeException.class) |
| 3 |
无参数匹配 |
@ExceptionHandler(Exception.class) |
@ExceptionHandler(BusinessException.class)
@ExceptionHandler(RuntimeException.class)
@ExceptionHandler(Exception.class)
7. @ControllerAdvice全局异常处理
7.1 @ControllerAdvice详解
7.2 @ControllerAdvice选择器
7.3 @ControllerAdvice注解定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class~? extends Annotation~[] annotations() default {};
Class~?~[] assignableTypes() default {};
}
7.4 @ModelAttribute全局数据绑定
@ControllerAdvice
public class GlobalControllerAdvice {
@ModelAttribute
public void addGlobalAttributes(Model model) {
model.addAttribute("appName", "My Application");
model.addAttribute("version", "1.0.0");
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
@ExceptionHandler(BusinessException.class)
@ResponseBody
public Result<Void> handleBusiness(BusinessException ex) {
return Result.fail(ex.getCode(), ex.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Result<Void> handleAll(Exception ex) {
return Result.fail(500, "系统错误");
}
}
7.5 @RestControllerAdvice简化写法
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public Result<Void> handleUserNotFound(UserNotFoundException ex) {
return Result.fail(404, ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidation(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.fail(400, msg);
}
@ExceptionHandler(AccessDeniedException.class)
public Result<Void> handleAccessDenied(AccessDeniedException ex) {
return Result.fail(403, "权限不足");
}
@ExceptionHandler(Throwable.class)
public Result<Void> handleAll(Throwable ex) {
log.error("未处理异常", ex);
return Result.fail(500, "系统繁忙");
}
}
8. 异常处理流程时序
8.1 完整异常处理时序
8.2 异常处理与拦截器的协同
8.3 异常处理决策流程
9. 拦截器与异常处理协同
9.1 典型场景:认证失败与异常处理
9.2 典型场景:业务异常与全局处理
9.3 拦截器中的异常处理
public class TransactionInterceptor implements HandlerInterceptor {
@Autowired
private TransactionManager transactionManager;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition());
request.setAttribute("txStatus", status);
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView mv) throws Exception {
TransactionStatus status = getTransactionStatus(request);
if (status != null && !status.isCompleted()) {
transactionManager.commit(status);
}
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
TransactionStatus status = getTransactionStatus(request);
if (status != null && !status.isCompleted()) {
if (ex != null) {
transactionManager.rollback(status);
} else {
transactionManager.commit(status);
}
}
request.removeAttribute("txStatus");
}
private TransactionStatus getTransactionStatus(HttpServletRequest request) {
return (TransactionStatus) request.getAttribute("txStatus");
}
}
9.4 常见问题与解决方案
9.4.1 preHandle返回false后的响应处理
public class UnifiedResponseInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (!validateRequest(request)) {
return sendError(response, 400, "请求参数不合法");
}
if (!authenticate(request)) {
return sendError(response, 401, "未授权访问");
}
return true;
}
private boolean sendError(HttpServletResponse response, int code, String message)
throws IOException {
response.setStatus(code);
response.setContentType("application/json;charset=UTF-8");
Result<Void> result = Result.fail(code, message);
response.getWriter().write(new ObjectMapper().writeValueAsString(result));
return false;
}
}
9.4.2 afterCompletion异常不中断清理流程
public class ResourceCleanupInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
try {
Connection connection = getConnection(request);
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
log.error("关闭数据库连接失败", e);
}
try {
ThreadLocalHolder.clear();
} catch (Exception e) {
log.error("清理ThreadLocal失败", e);
}
}
}
9.4.3 拦截器之间的数据共享
public class ContextInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
RequestContext context = new RequestContext();
context.setRequestId(UUID.randomUUID().toString());
context.setStartTime(System.currentTimeMillis());
request.setAttribute("__CONTEXT__", context);
return true;
}
}
public class AuditInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
RequestContext context = (RequestContext) request.getAttribute("__CONTEXT__");
if (context != null) {
long duration = System.currentTimeMillis() - context.getStartTime();
auditService.record(context.getRequestId(), request.getRequestURI(), duration, ex);
}
}
}
9.4.4 REST API 与 MVC 的异常处理差异
| 场景 |
REST API |
MVC |
| 返回格式 |
JSON |
视图 |
| 使用注解 |
@RestControllerAdvice |
@ControllerAdvice |
| 返回类型 |
ResponseEntity, Result |
ModelAndView, String |
| 状态码 |
HTTP状态码 |
错误视图 |
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusiness(BusinessException ex) {
return Result.fail(ex.getCode(), ex.getMessage());
}
}
@ControllerAdvice
public class MvcExceptionHandler {
@ExceptionHandler(BusinessException.class)
public String handleBusiness(BusinessException ex, Model model) {
model.addAttribute("error", ex.getMessage());
return "error/business";
}
}
9.4.5 拦截器中的异步处理
public class AsyncInterceptor implements AsyncHandlerInterceptor {
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
releaseResources(request);
}
}
9.4.6 拦截器与过滤器的区别
| 特性 |
Filter |
HandlerInterceptor |
| 来源 |
Servlet API |
Spring MVC |
| 执行时机 |
DispatcherServlet之前 |
DispatcherServlet内部 |
| IOC容器 |
不属于 |
属于Spring IOC容器 |
| 异常处理 |
FilterChain.doFilter外 |
@ExceptionHandler处理 |
| 典型用途 |
字符编码、XSS、CORS |
认证授权、日志、性能监控 |
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return userService.getCurrentUser() != null;
}
}
9.4.7 性能监控拦截器
@Component
public class PerformanceInterceptor implements HandlerInterceptor {
private static final long SLOW_REQUEST_THRESHOLD = 1000;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("__START_TIME__", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
long duration = System.currentTimeMillis() - (Long) request.getAttribute("__START_TIME__");
if (duration > SLOW_REQUEST_THRESHOLD) {
log.warn("慢请求: {} {} - {}ms", request.getMethod(), request.getRequestURI(), duration);
}
log.info("请求完成: {} {} - {}ms - {}",
request.getMethod(), request.getRequestURI(), duration, response.getStatus());
}
}
10. 实战:完整登录认证方案
10.1 项目结构
10.2 统一响应结果
public class Result<T> {
private int code;
private String message;
private T data;
private long timestamp = System.currentTimeMillis();
public static <T> Result<T> success(T data) {
Result<T> r = new Result<>();
r.code = 200;
r.message = "success";
r.data = data;
return r;
}
public static <T> Result<T> fail(int code, String message) {
Result<T> r = new Result<>();
r.code = code;
r.message = message;
return r;
}
}
public class BusinessException extends RuntimeException {
private final int code;
public BusinessException(int code, String message) { super(message); this.code = code; }
public int getCode() { return code; }
}
10.3 认证拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
return true;
}
String token = extractToken(request);
if (token == null) {
return sendError(response, 401, "请先登录");
}
User user = userService.validateToken(token);
if (user == null) {
return sendError(response, 401, "Token无效或已过期");
}
UserContext.setCurrentUser(user);
request.setAttribute("currentUser", user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
UserContext.remove();
}
private String extractToken(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
return token.substring(7);
}
return request.getParameter("token");
}
private boolean sendError(HttpServletResponse response, int code, String message)
throws IOException {
response.setStatus(code);
response.setContentType("application/json;charset=UTF-8");
Result<Void> result = Result.fail(code, message);
response.getWriter().write(new ObjectMapper().writeValueAsString(result));
return false;
}
}
10.4 全局异常处理
@RestControllerAdvice(basePackages = "com.example.web.controller")
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusiness(BusinessException ex) {
return Result.fail(ex.getCode(), ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidation(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining("; "));
return Result.fail(400, msg);
}
@ExceptionHandler(AccessDeniedException.class)
public Result<Void> handleAccessDenied(AccessDeniedException ex) {
return Result.fail(403, "权限不足");
}
@ExceptionHandler(NoHandlerFoundException.class)
public Result<Void> handleNotFound(NoHandlerFoundException ex) {
return Result.fail(404, "资源不存在");
}
@ExceptionHandler(Exception.class)
public Result<Void> handleAll(Exception ex) {
log.error("未处理异常", ex);
return Result.fail(500, "系统繁忙,请稍后重试");
}
}
10.5 限流拦截器
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
private final Map<String, AtomicInteger> counters = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
@Value("${rate.limit.max-requests:100}")
private int maxRequests;
@Value("${rate.limit.window-seconds:60}")
private int windowSeconds;
@PostConstruct
public void init() {
scheduler.scheduleAtFixedRate(() -> {
counters.clear();
log.info("限流计数器已重置");
}, windowSeconds, windowSeconds, TimeUnit.SECONDS);
}
@PreDestroy
public void destroy() {
scheduler.shutdown();
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String clientKey = getClientKey(request);
AtomicInteger counter = counters.computeIfAbsent(clientKey,
k -> new AtomicInteger(0));
int currentCount = counter.incrementAndGet();
if (currentCount > maxRequests) {
log.warn("请求限流触发: client={}, count={}, limit={}",
clientKey, currentCount, maxRequests);
writeRateLimitResponse(response, maxRequests, windowSeconds);
return false;
}
response.setHeader("X-RateLimit-Limit", String.valueOf(maxRequests));
response.setHeader("X-RateLimit-Remaining",
String.valueOf(Math.max(0, maxRequests - currentCount)));
response.setHeader("X-RateLimit-Reset",
String.valueOf(System.currentTimeMillis() / 1000 + windowSeconds));
return true;
}
private String getClientKey(HttpServletRequest request) {
User user = UserContext.getCurrentUser();
if (user != null) {
return "user:" + user.getId();
}
String ip = getClientIp(request);
return "ip:" + ip;
}
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip.split(",")[0].trim();
}
private void writeRateLimitResponse(HttpServletResponse response,
int limit,
int window) throws IOException {
response.setStatus(429);
response.setContentType("application/json;charset=UTF-8");
Result<Void> result = Result.fail(429,
String.format("请求过于频繁,请%d秒后重试", window));
response.getWriter().write(new ObjectMapper().writeValueAsString(result));
}
}
10.6 完整配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private TenantInterceptor tenantInterceptor;
@Autowired
private AuthInterceptor authInterceptor;
@Autowired
private RateLimitInterceptor rateLimitInterceptor;
@Autowired
private LoggingInterceptor loggingInterceptor;
@Autowired
private PerformanceInterceptor performanceInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tenantInterceptor)
.addPathPatterns("/api/**").order(1);
registry.addInterceptor(rateLimitInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**").order(2);
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login", "/api/register").order(3);
registry.addInterceptor(performanceInterceptor)
.addPathPatterns("/api/**").order(4);
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/api/**").order(5);
}
}
10.7 执行流程总结
总结
拦截器执行流程
异常处理体系
| 组件 |
职责 |
处理范围 |
HandlerExceptionResolver |
异常解析接口 |
所有异常 |
SimpleMappingExceptionResolver |
视图异常映射 |
视图异常 |
DefaultHandlerExceptionResolver |
Servlet标准异常 |
HTTP状态异常 |
ExceptionHandlerExceptionResolver |
@ExceptionHandler |
业务异常 |
@ExceptionHandler |
方法级异常处理 |
Controller内 |
@ControllerAdvice |
全局异常处理 |
所有Controller |
核心要点
- 拦截器preHandle返回false:跳过后续处理,直接触发afterCompletion
- postHandle不执行时机:Controller抛出异常时不执行
- afterCompletion始终执行:无论成功还是异常,都会逆序执行
- 异常处理链遍历:按顺序遍历HandlerExceptionResolver,找到第一个处理的为止
- @ExceptionHandler优先级:精确匹配 > 祖先类匹配 > 无参数匹配
- @ControllerAdvice选择器:可通过basePackages、annotations、assignableTypes限制范围
- 拦截器与异常处理协同:拦截器处理认证失败直接响应,异常处理处理业务异常
所有评论(0)