SpringMVC 拦截器
拦截器接口-HandlerInterceptor
自定义的拦截器,需要继承HandlerInterceptor接口,并且实现HandlerInterceptor中提供的三个方法:
1. preHandle 方法会在请求处理前被调用。这个方法返回boolean值,如果返回true则继续往下执行,如果返回false则中断。
2. postHandle 方法会在请求处理后,继续调用。
3. afterCompletion 方法会在视图渲染之后调用。
代码:
package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; public interface HandlerInterceptor { boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception; void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception; }
在什么地方调用该接口方法呢
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.web.servlet; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final Object handler; private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex; public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[])null); } public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) { this.interceptorIndex = -1; if(handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain)handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } } public Object getHandler() { return this.handler; } public void addInterceptor(HandlerInterceptor interceptor) { this.initInterceptorList().add(interceptor); } public void addInterceptors(HandlerInterceptor... interceptors) { if(!ObjectUtils.isEmpty(interceptors)) { this.initInterceptorList().addAll(Arrays.asList(interceptors)); } } private List<HandlerInterceptor> initInterceptorList() { if(this.interceptorList == null) { this.interceptorList = new ArrayList(); if(this.interceptors != null) { this.interceptorList.addAll(Arrays.asList(this.interceptors)); } } this.interceptors = null; return this.interceptorList; } public HandlerInterceptor[] getInterceptors() { if(this.interceptors == null && this.interceptorList != null) { this.interceptors = (HandlerInterceptor[])this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]); } return this.interceptors; } //调用preHandle boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = this.getInterceptors(); if(!ObjectUtils.isEmpty(interceptors)) { for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) { HandlerInterceptor interceptor = interceptors[i]; if(!interceptor.preHandle(request, response, this.handler)) { this.triggerAfterCompletion(request, response, (Exception)null); return false; } } } return true; } //调用postHandle void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = this.getInterceptors(); if(!ObjectUtils.isEmpty(interceptors)) { for(int i = interceptors.length - 1; i >= 0; --i) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } //调用afterCompletion void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = this.getInterceptors(); if(!ObjectUtils.isEmpty(interceptors)) { for(int i = this.interceptorIndex; i >= 0; --i) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable var8) { logger.error("HandlerInterceptor.afterCompletion threw exception", var8); } } } } void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) { HandlerInterceptor[] interceptors = this.getInterceptors(); if(!ObjectUtils.isEmpty(interceptors)) { for(int i = interceptors.length - 1; i >= 0; --i) { if(interceptors[i] instanceof AsyncHandlerInterceptor) { try { AsyncHandlerInterceptor ex = (AsyncHandlerInterceptor)interceptors[i]; ex.afterConcurrentHandlingStarted(request, response, this.handler); } catch (Throwable var6) { logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", var6); } } } } } public String toString() { if(this.handler == null) { return "HandlerExecutionChain with no handler"; } else { StringBuilder sb = new StringBuilder(); sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]"); if(!CollectionUtils.isEmpty(this.interceptorList)) { sb.append(" and ").append(this.interceptorList.size()).append(" interceptor"); if(this.interceptorList.size() > 1) { sb.append("s"); } } return sb.toString(); } } }
那么在什么地方调用HandlerExecutionChain中的applyPreHandle,applyPostHandle,triggerAfterCompletion方法呢
嗯,在大名鼎鼎的DispatcherServlet.class中,这个类就是SpringMVC的核心。
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 err = null; Exception dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if(mappedHandler == null || mappedHandler.getHandler() == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if(isGet || "HEAD".equals(method)) { long lastModified = ex.getLastModified(request, mappedHandler.getHandler()); if(this.logger.isDebugEnabled()) { this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } //调用applyPreHandle if(!mappedHandler.applyPreHandle(processedRequest, response)) { return; } err = ex.handle(processedRequest, response, mappedHandler.getHandler()); if(asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, err);
//调用applyPostHandle mappedHandler.applyPostHandle(processedRequest, response, err); } catch (Exception var19) { dispatchException = var19; } this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException); } catch (Exception var20) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20); } catch (Error var21) { this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21); } finally { if(asyncManager.isConcurrentHandlingStarted()) { if(mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if(multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
这边还有一个网上牛人的注释版
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // processedRequest是经过checkMultipart方法处理过的request请求 HttpServletRequest processedRequest = request; /** * Handler execution chain, consisting of handler object and any handler * interceptors. Returned by HandlerMapping's HandlerMapping.getHandler * method. 看看HandlerExecutionChain类的属性就很清楚了: * public class HandlerExecutionChain { private final Object handler; //这个就是和该请求对应的handler处理方法 //里面记录了所有的(any handler interceptors)和该请求相关的拦截器 private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; //... } * */ 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.Return a handler // and any interceptors for this request. /* * 得到的mappedHandler包含一个请求的handler处理方法以及与该请求相关的所有拦截器 * * DispatcherServlet.getHandler方法会在底层调用HandlerMapping.getHandler方法 * ,这个方法中会遍 历DispatcherServlet中的private List<HandlerMapping> * handlerMappings链表,找到能够处理当前 request请求的第一个HandlerMapping实例并返回: * protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } * */ mappedHandler = getHandler(processedRequest); // 如果没有找到和该请求相对应的mappedHandler,那么就会直接返回,并应答noHandlerFound异常 if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. /* * HandlerAdapter: 它是一个接口public interface HandlerAdapter * 看看源码上的说明:The DispatcherServlet accesses all installed * handlers through this interface, meaning that it does not * contain code specific to any handler type. * * 从后面的源码看出,在使用@RequestMapping注解标注handler方法的时候,获取到的是HandlerAdapter的 * RequestMappingHandlerAdapter实现类的一个对象。 * * 可以看看DispatcherServlet.getHandlerAdapter方法的定义,这个对理解上回很有帮助,我们会发现 * ,getHandlerAdapter 方法和上面提到的getHandler方法一样都是寻找第一个可用的作为返回结果: * * protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { //this.handlerAdapters的定义是 private List<HandlerAdapter> handlerAdapters for (HandlerAdapter ha : this.handlerAdapters) { if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); } * */ 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 (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response) .checkNotModified(lastModified) && isGet) { return; } } // Apply preHandle methods of registered interceptors. /* * 会调用所有注册拦截器的preHandle方法,如果preHandle方法的返回结果为true,则会继续执行下面的程序, * 否则会直接返回。 * * 分析一下HandlerExecutionChain.applyPreHandle方法的源码 : boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { //从上面的HandlerExecutionChain定义处可以看见有个interceptors,还有一个interceptorList。不知道有什么区别??! HandlerInterceptor[] interceptors = getInterceptors(); //如果已经注册有拦截器,则遍历拦截器 if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; //如果注册拦截器的preHandle方法返回一个false,则该applyPreHandle方法就会返回false,从而在doDispatcher中的代码就不会往下执行了 if (!interceptor.preHandle(request, response, this.handler)) { //这个方法要注意,它会调用所有已经成功执行的拦截器的afterCompletion方法,而且是反序调用的过程,可以分析triggerAfterCompletion //的源代码,主要是利用interceptorIndex反减的方式实现的。下面是源码的英文注释: //Trigger afterCompletion callbacks on the mapped HandlerInterceptors. //Will just invoke afterCompletion for all interceptors whose preHandle invocation //has successfully completed and returned true. triggerAfterCompletion(request, response, null); return false; } //没成功执行一个拦截器的preHandle方法,其interceptorIndex就会增加1;原始值为-1。 this.interceptorIndex = i; } } return true; } * * * 顺带看看triggerAfterCompletion的源代码,很容易理解为什么拦截器的afterCompletion方法是反序执行的: * void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { 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); } } } } * * */ if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. /* * 在这个函数里面会真正的执行request请求相对于的handler方法,可以想象:在真正调用方法之前还会有很多的 * 先前处理。在这里仅仅是分析出大概的代码执行流程,其细节的部分在后面的单独模块源码分析的时候做详细的讲解。 * 上面讲解到HandlerAdapter是一个接口:public interface HandlerAdapter,那么必然会有很多 * 中实现类,在采用注解@RequstMapping的方式标注handler的情况下,ha.handle方法会在底层调用具体的 * HandlerAdapter类实现方法RequestMappingHandlerAdapter.handleInternal * * 分析一下RequestMappingHandlerAdapter.handleInternal的源代码: protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //好像是看control的类定义处是否使用了@SessionAttributes注解,checkAndPrepare方法有什么作用??? if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { // Always prevent caching in case of session attribute management. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { // Uses configured default cacheSeconds setting. checkAndPrepare(request, response, true); } // Execute invokeHandlerMethod in synchronized block if required. // 这里是个值得注意的地方,synchronizeOnSession的值默认为false,如果通过某个方法使得其为true,那么request对应的handler // 将会被放在同步快中进行处理。在什么时机下,使用什么方法才能将其设置为true呢??? if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); // 将handler放在同步块中处理 synchronized (mutex) { return invokeHandleMethod(request, response, handlerMethod); } } } //在invokeHandleMethod中会①将所有标注有@ModelAttrib的方法都执行一遍,②调用invokeAndHandle(webRequest, mavContainer) //方法,在这里面调用handler方法,③最后调用getModelAndView(mavContainer, modelFactory, webRequest)方法的到ModelAndView。 //invokeHandleMethod这个方法还有很多东西要分析,留在后面。 //从上面的③我们可以看出,无论handler采用哪种模型化处理方式,最后都是将结果转化为ModelAndView return invokeHandleMethod(request, response, handlerMethod); } */ mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, mv); /* * 调用request相关的拦截器的postHandle方法,注意,这个也是反序调用的。看看源代码: * void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { //注意,这里也是反序执行,而且是所有成功执行了的postHandle拦截器 for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; //这里传入的参数中有mv,也就是说,我们是有办法在拦截器的postHandle方法中修改已经返回的mv interceptor.postHandle(request, response, this.handler, mv); } } } */ mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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); } } } }
http://www.cnblogs.com/lj95801/p/4961456.html?utm_source=tuicool&utm_medium=referral