SpringMVC拦截器使用流程和源码分析
作者:互联网
1、SpringMVC拦截器的使用流程
1)、在spring-servlet.xml中配置拦截器信息。
<!-- 调试拦截器--> <mvc:interceptors> <!-- 配置某个拦截器,默认拦截所有请求 --> <!-- <bean class="com.lxy.controller.FilterController"></bean>--> <!-- 配置某个拦截器更详细的信息 --> <mvc:interceptor> <!--只拦截test01请求--> <mvc:mapping path="/test01"/> <bean class="com.lxy.controller.FilterController"> </bean> </mvc:interceptor> </mvc:interceptors>
2)、写自己的拦截器并实现 HandlerInterceptor接口
public class MyFilter implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
重点是实现 preHandle、postHandle、afterCompletion三个方法
2、SpringMVC拦截器运行流程
正常流程:
拦截器的preHandle--->目标方法---->拦截器的postHandle---->页面----->拦截器的afterCompletion
其他流程:
只要preHandle不放行,就没有下面的流程。 只要放行了,afterCompletion都会执行
3、SpringMVC拦截器源码分析
SpringMVC的核心方法doDispatch() 源码如下 ---------------之前的随笔也分析过 ------------------
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 在目标方法执行之前,会先执行preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 执行目标方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv);
// 在执行完目标方法之后,会执行拦截器的postHandler方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); }
// 渲染页面,并在该方法中执行afterCompletion方法 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) {
// 即使上面执行的方法抛出了异常,afterCompletion的方法依然会被执行 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
1)、preHandle方法是如何执行的(applyPreHandle方法)
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 得到所有的拦截器 HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) {
// 循环正序遍历所有的拦截器 for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i];
// 执行拦截器方法,并返回true/false 来当前方法,preHandler是否放行了 if (!interceptor.preHandle(request, response, this.handler)) {
// 执行到这,说明preHandler返回的是false,就是不放行,那么就执行完下面方法(afterCompletion方法的执行方法),直接返回,不纪录拦截器索引
// 由于没有纪录当前拦截器索引,所以即使执行了下面方法,当前拦截器的afterCompletion也不会被执行 triggerAfterCompletion(request, response, null); return false; }
// 纪录拦截器索引,为之后执行afterCompletion方法做准备 this.interceptorIndex = i; } } return true;
2)、postHandle方法是如何执行的(applyPostHandle)
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) {
// 逆序遍历所有的拦截器,并执行postHandler方法 for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } }
3)、afterCompletion方法是如何执行的
先来到 processDispatchResult方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; // 先进行页面渲染 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } // 页面渲染完成后,执行afterCompletion方法 if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
页面渲染完成之后,执行 triggerAfterCompletion 方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历所有之前preHandle方法放行的拦截器,interceptorIndex就是之前在执行preHandle方法时候,如果返回的是true就纪录一下 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); } } } }
标签:Exception,拦截器,SpringMVC,mappedHandler,request,源码,response,afterCompletion 来源: https://www.cnblogs.com/lxy-java/p/12936334.html