spring mvc 拦截器 (HandlerInterceptor )

发布于:2025-09-14 ⋅ 阅读:(20) ⋅ 点赞:(0)

Spring MVC 的 拦截器(Interceptor)可以在请求到达 Controller 之前、执行 Controller 之后、视图渲染之前/之后进行拦截和处理。拦截器主要用于日志记录、权限校验、性能监控、通用数据处理等场景。

拦截器的核心接口是HandlerInterceptor ,它定义了三个拦截器行为方法

public interface HandlerInterceptor {
    // 请求进入 Controller 之前调用,返回 true 才会继续向下执行
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    // Controller 方法调用之后,视图渲染之前调用
    default void postHandle(HttpServletRequest request, HttpServletResponse response,
                            Object handler, ModelAndView modelAndView) throws Exception {}

    // 整个请求完成之后调用,一般用于清理资源或异常处理
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                 Object handler, Exception ex) throws Exception {}
}

执行流程

拦截器链的执行顺序类似于 责任链模式:

  1. 按配置顺序调用 preHandle()。如果返回 false,后续的拦截器和 Controller 就不会执行。
  2. 执行目标 Controller方法
  3. 按配置顺序 逆序调用 postHandle()。
  4. 最后按配置顺序 逆序调用 afterCompletion()。

注册拦截器

在 Spring Boot 或 Spring MVC 中,需要通过 WebMvcConfigurer 注册拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")       // 拦截所有请求
                .excludePathPatterns("/login", "/error"); // 放行路径
    }
}

触发时机

拦截器被封装成HandlerExecutionChain 执行链。在DispatchServlet会调用HandlerExecutionChain。

啊doDispatch()方法内通过getHandler()方法获取对应的HandlerExecutionChain

DispatchServlet#doDispatch()相关代码

HandlerExecutionChain mappedHandler = null;
//获取HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
  noHandlerFound(processedRequest, response);
  return;
}

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//调用拦截器preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

// 执行目标controller方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
	return;
}

applyDefaultViewName(processedRequest, mv);
//执行拦截器PostHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);

applyPreHandle方法就是拿出所有的HandlerInterceptor依次调用

HandlerExecutionChain #applyPreHandle()

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		for (int i = 0; i < this.interceptorList.size(); i++) {
			HandlerInterceptor interceptor = this.interceptorList.get(i);
			if (!interceptor.preHandle(request, response, this.handler)) {
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
		return true;
	}