在 Web应用开发中,拦截器(Interceptor)是一种非常重要的机制,能够在请求处理的各个阶段进行前置和后置处理。Spring框架提供了强大且灵活的拦截器机制,使开发者能够轻松地在请求处理流程中插入自定义逻辑。理解Spring拦截链的实现原理,不仅有助于我们更好地使用Spring提供的功能,还能让我们在需要时自定义复杂的请求处理逻辑。
简单来说,拦截链是一个处理请求的拦截器列表,按照一定的顺序,一个一个地拦截并处理请求。每个拦截器都可以在请求处理前、处理后或完成后执行一些逻辑。比如,我们可能需要在所有请求处理前进行权限验证,在处理后记录日志,或者在请求完成后释放资源。这些操作可以通过定义不同的拦截器来实现,每个拦截器负责一个特定的任务。
在Spring MVC中,拦截器链是通过HandlerInterceptor接口及其实现类来实现的。Spring的DispatcherServlet作为前端控制器(Front Controller),负责协调请求的各个阶段,包括调用拦截器。拦截器链的实现允许多个拦截器按照一定的顺序对请求进行处理。每个拦截器都有机会在请求处理前后执行特定的逻辑,这为我们在请求处理流程中插入自定义逻辑提供了极大的灵活性。
HandlerInterceptor:HandlerInterceptor接口定义了拦截器的基本行为。通过实现该接口,可以在请求处理的不同阶段插入自定义逻辑,如请求前、请求后或完成后的处理。
这个流程确保了拦截器可以在请求处理的不同阶段插入逻辑,例如验证、日志记录、性能监控等。
public class DispatcherServlet extends FrameworkServlet { // ...其他代码... @Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // ...初始化上下文... // 堆代码 duidaima.com // 1. 查找处理器 HandlerExecutionChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(request, response); return; } HttpServletRequest webRequest = createWebRequest(request, response); try { // 2. 应用拦截器的preHandle方法 HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); if (!applyPreHandle(processedRequest, response, mappedHandler, interceptors)) { return; } // 3. 调用处理器 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 4. 应用拦截器的postHandle方法 applyPostHandle(processedRequest, response, mappedHandler, mv, interceptors); // 5. 渲染视图 render(mv, request, response); // 6. 应用拦截器的afterCompletion方法 triggerAfterCompletion(processedRequest, response, mappedHandler, null, interceptors); } catch (Exception ex) { // 异常处理 // ... } } // ...其他代码... }
从上面的代码可以看出,DispatcherServlet在处理请求的过程中,依次执行了查找处理器、应用拦截器的preHandle、调用处理器、应用拦截器的postHandle、渲染视图以及应用拦截器的afterCompletion方法的步骤。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { return this.handlerMappings.getHandler(request); }这里,handlerMappings是一个List<HandlerMapping>,Spring会按照顺序遍历这些HandlerMapping,直到找到匹配的处理器。
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 基于请求URL和HTTP方法,查找匹配的HandlerMethod // 返回一个HandlerMethod对象,包含控制器实例和方法信息 }5.3 HandlerAdapter的适配逻辑
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handlerAdapter.handle(request, response, handler); }handlerAdapter是一个HandlerAdapter接口的实现,通过supports方法确定是否适配,然后调用handle方法执行处理器。
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 调用Controller方法,处理请求 // 绑定请求参数,执行数据绑定和验证 // 返回ModelAndView对象 }5.4 HandlerInterceptor的执行流程
public class HandlerExecutionChain { private final Object handler; private final List<HandlerInterceptor> interceptors; // Getters and constructors }在applyPreHandle方法中,DispatcherServlet会按照顺序调用每个拦截器的preHandle方法:
protected boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler) throws Exception { HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); if(!ObjectUtils.isEmpty(interceptors)) { for (HandlerInterceptor interceptor : interceptors) { if (!interceptor.preHandle(request, response, mappedHandler.getHandler())) { triggerAfterCompletion(request, response, mappedHandler, null, interceptors); return false; } } } return true; }类似地,在applyPostHandle和triggerAfterCompletion方法中,拦截器的postHandle和afterCompletion方法依次被调用,且顺序与preHandle相反。
public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 请求处理前执行 System.out.println("Pre Handle method is Calling"); return true; // 返回true继续流程,返回false则中断 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 请求处理后但视图渲染前执行 System.out.println("Post Handle method is Calling"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 视图渲染后执行 System.out.println("Request and Response is completed"); } }注册这个拦截器可以通过Java配置或XML配置。在Spring Boot中,可以通过实现WebMvcConfigurer接口来进行配置:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/**") // 拦截所有请求 .excludePathPatterns("/login"); // 排除特定路径 } }通过这样的配置,MyInterceptor就会拦截所有请求,除了/login路径。
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new FirstInterceptor()); registry.addInterceptor(new SecondInterceptor()); }执行顺序:
FirstInterceptor.preHandle SecondInterceptor.preHandle SecondInterceptor.postHandle FirstInterceptor.postHandle SecondInterceptor.afterCompletion FirstInterceptor.afterCompletion
这种设计允许后注册的拦截器优先执行后置逻辑和完成逻辑。