SpringMVC源码总结(十一)mvc:interceptors拦截器介绍

本文章针对mvc:interceptors标签进行介绍,它的注册过程以及在访问时的拦截过程。 

首先说下接口HandlerInterceptor,它有如下三个方法:
 
Java代码   收藏代码
  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  2.         throws Exception;  
  3.   
  4. void postHandle(  
  5.             HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
  6.             throws Exception;  
  7.   
  8. void afterCompletion(  
  9.             HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
  10.             throws Exception;  


正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。 

AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。 

HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。 

然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
 
Java代码   收藏代码
  1. @Override  
  2.     public boolean preHandle(HttpServletRequest request,  
  3.             HttpServletResponse response, Object handler) throws Exception {  
  4.         System.out.println("preHandle");  
  5.         return super.preHandle(request, response, handler);  
  6.     }  
  7.   
  8.     @Override  
  9.     public void postHandle(HttpServletRequest request,  
  10.             HttpServletResponse response, Object handler,  
  11.             ModelAndView modelAndView) throws Exception {  
  12.         System.out.println("postHandle");  
  13.         super.postHandle(request, response, handler, modelAndView);  
  14.     }  
  15.   
  16.     @Override  
  17.     public void afterCompletion(HttpServletRequest request,  
  18.             HttpServletResponse response, Object handler, Exception ex)  
  19.             throws Exception {  
  20.         System.out.println("afterCompletion");  
  21.         super.afterCompletion(request, response, handler, ex);  
  22.     }  
  23.   
  24.     @Override  
  25.     public void afterConcurrentHandlingStarted(HttpServletRequest request,  
  26.             HttpServletResponse response, Object handler) throws Exception {  
  27.         System.out.println("afterConcurrentHandlingStarted");  
  28.         super.afterConcurrentHandlingStarted(request, response, handler);  
  29.     }  

没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。 
该接口的基本内容说完了,然后就看下它的配置说明:
 
Java代码   收藏代码
  1. <mvc:interceptors path-matcher="xxx">  
  2.         <mvc:interceptor>  
  3.             <mvc:mapping path="xxx"/>  
  4.             <mvc:exclude-mapping path="xxxx"/>  
  5.             <bean class="xxxx"></bean>  
  6.         </mvc:interceptor>  
  7.         <bean class="com.lg.mvc.interceptor.LoginInterceptor" />  
  8.     </mvc:interceptors>  

其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。 

而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。 
对于本工程来说具体的配置如下:
 
Java代码   收藏代码
  1. <mvc:interceptors>  
  2.         <bean class="com.lg.mvc.interceptor.LoginInterceptor" />  
  3.     </mvc:interceptors>  

然后就进行源代码分析: 
如何来处理xml文件中所配置的这些HandlerInterceptor的呢? 
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
 
Java代码   收藏代码
  1. public BeanDefinition parse(Element element, ParserContext parserContext) {  
  2.         CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));  
  3.         parserContext.pushContainingComponent(compDefinition);  
  4. //判断是否自定义了PathMatcher  
  5.         RuntimeBeanReference pathMatcherRef = null;  
  6.         if (element.hasAttribute("path-matcher")) {  
  7.             pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));  
  8.         }  
  9. //获取所有的interceptor,在这里我们可以看到所有的interceptor最终都会构建成一个  
  10. //MappedInterceptor  
  11.         List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean""ref""interceptor");  
  12.         for (Element interceptor : interceptors) {  
  13.             RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);  
  14.             mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));  
  15.             mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
  16.   
  17.             ManagedList<String> includePatterns = null;  
  18.             ManagedList<String> excludePatterns = null;  
  19.             Object interceptorBean;  
  20.             if ("interceptor".equals(interceptor.getLocalName())) {  
  21.                 includePatterns = getIncludePatterns(interceptor, "mapping");  
  22.                 excludePatterns = getIncludePatterns(interceptor, "exclude-mapping");  
  23.                 Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean""ref").get(0);  
  24.                 interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null);  
  25.             }  
  26.             else {  
  27.                 interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null);  
  28.             }  
  29.             mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);  
  30.             mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);  
  31.             mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean);  
  32.   
  33.             if (pathMatcherRef != null) {  
  34.                 mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef);  
  35.             }  
  36.   
  37.             String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);  
  38.             parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));  
  39.         }  
  40.   
  41.         parserContext.popAndRegisterContainingComponent();  
  42.         return null;  
  43.     }  

这里就引出来MappedInterceptor的结构类型:  
Java代码   收藏代码
  1. private final String[] includePatterns;  
  2.   
  3.     private final String[] excludePatterns;  
  4.   
  5.     private final HandlerInterceptor interceptor;  
  6.   
  7.     private PathMatcher pathMatcher;  

到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:  
Java代码   收藏代码
  1. public boolean matches(String lookupPath, PathMatcher pathMatcher) {  
  2.         PathMatcher pathMatcherToUse = (this.pathMatcher != null) ? this.pathMatcher : pathMatcher;  
  3.         if (this.excludePatterns != null) {  
  4.             for (String pattern : this.excludePatterns) {  
  5.                 if (pathMatcherToUse.match(pattern, lookupPath)) {  
  6.                     return false;  
  7.                 }  
  8.             }  
  9.         }  
  10.         if (this.includePatterns == null) {  
  11.             return true;  
  12.         }  
  13.         else {  
  14.             for (String pattern : this.includePatterns) {  
  15.                 if (pathMatcherToUse.match(pattern, lookupPath)) {  
  16.                     return true;  
  17.                 }  
  18.             }  
  19.             return false;  
  20.         }  
  21.     }  

这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。 
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。 

谁会是他们的使用者呢?我们慢慢来看: 
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
 
Java代码   收藏代码
  1. private final Object handler;  
  2.   
  3.     private HandlerInterceptor[] interceptors;  
  4.   
  5.     private List<HandlerInterceptor> interceptorList;  
  6.   
  7.     private int interceptorIndex = -1;  

既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。 
使用者:AbstractHandlerMapping,它的属性有:
 
Java代码   收藏代码
  1.        private PathMatcher pathMatcher = new AntPathMatcher();  
  2.   
  3. private final List<Object> interceptors = new ArrayList<Object>();  
  4.   
  5. private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();  
  6.   
  7. private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();  

这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:  
Java代码   收藏代码
  1. protected void initApplicationContext() throws BeansException {  
  2.         extendInterceptors(this.interceptors);  
  3.         detectMappedInterceptors(this.mappedInterceptors);  
  4.         initInterceptors();  
  5.     }  

detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:  
Java代码   收藏代码
  1. protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {  
  2.         mappedInterceptors.addAll(  
  3.                 BeanFactoryUtils.beansOfTypeIncludingAncestors(  
  4.                         getApplicationContext(), MappedInterceptor.classtruefalse).values());  
  5.     }  

全部存放到AbstractHandlerMapping的mappedInterceptors属性上。 
然后我们继续看看在请求到来时的具体拦截过程:
 
Java代码   收藏代码
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.         HttpServletRequest processedRequest = request;  
  3.         HandlerExecutionChain mappedHandler = null;  
  4.         boolean multipartRequestParsed = false;  
  5.   
  6.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  7.   
  8.         try {  
  9.             ModelAndView mv = null;  
  10.             Exception dispatchException = null;  
  11.   
  12.             try {  
  13.                 processedRequest = checkMultipart(request);  
  14.                 multipartRequestParsed = (processedRequest != request);  
  15.   
  16.                 // Determine handler for the current request.  
  17.                 mappedHandler = getHandler(processedRequest);  
  18. //略  
  19. }  

对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:  
Java代码   收藏代码
  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  2.         for (HandlerMapping hm : this.handlerMappings) {  
  3.             if (logger.isTraceEnabled()) {  
  4.                 logger.trace(  
  5.                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
  6.             }  
  7.             HandlerExecutionChain handler = hm.getHandler(request);  
  8.             if (handler != null) {  
  9.                 return handler;  
  10.             }  
  11.         }  
  12.         return null;  
  13.     }  

这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。  
Java代码   收藏代码
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  2.         Object handler = getHandlerInternal(request);  
  3.         if (handler == null) {  
  4.             handler = getDefaultHandler();  
  5.         }  
  6.         if (handler == null) {  
  7.             return null;  
  8.         }  
  9.         // Bean name or resolved handler?  
  10.         if (handler instanceof String) {  
  11.             String handlerName = (String) handler;  
  12.             handler = getApplicationContext().getBean(handlerName);  
  13.         }  
  14.         return getHandlerExecutionChain(handler, request);  
  15.     }  

这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:  
Java代码   收藏代码
  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
  2.         HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?  
  3.                 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));  
  4.         chain.addInterceptors(getAdaptedInterceptors());  
  5.   
  6.         String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);  
  7.         for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {  
  8.             if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {  
  9.                 chain.addInterceptor(mappedInterceptor.getInterceptor());  
  10.             }  
  11.         }  
  12.   
  13.         return chain;  
  14.     }  

对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。 

至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
 
Java代码   收藏代码
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.         HttpServletRequest processedRequest = request;  
  3.         HandlerExecutionChain mappedHandler = null;  
  4.         boolean multipartRequestParsed = false;  
  5.   
  6.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  7.   
  8.         try {  
  9.             ModelAndView mv = null;  
  10.             Exception dispatchException = null;  
  11.   
  12.             try {  
  13.                 processedRequest = checkMultipart(request);  
  14.                 multipartRequestParsed = (processedRequest != request);  
  15.   
  16.                 // Determine handler for the current request.  
  17.                 mappedHandler = getHandler(processedRequest);  
  18.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {  
  19.                     noHandlerFound(processedRequest, response);  
  20.                     return;  
  21.                 }  
  22.   
  23.                 // Determine handler adapter for the current request.  
  24.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  25.   
  26.                 // Process last-modified header, if supported by the handler.  
  27.                 String method = request.getMethod();  
  28.                 boolean isGet = "GET".equals(method);  
  29.                 if (isGet || "HEAD".equals(method)) {  
  30.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  31.                     if (logger.isDebugEnabled()) {  
  32.                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);  
  33.                     }  
  34.                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
  35.                         return;  
  36.                     }  
  37.                 }  
  38. //重点1 这里执行interceptor的preHandle方法  
  39.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
  40.                     return;  
  41.                 }  
  42. //这里执行处理函数  
  43.                 try {  
  44.                     // Actually invoke the handler.  
  45.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  46.                 }  
  47.                 finally {  
  48.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  49.                         return;  
  50.                     }  
  51.                 }  
  52.   
  53.                 applyDefaultViewName(request, mv);  
  54. //重点2:这里执行interceptor的postHandle方法  
  55.                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
  56.             }  
  57.             catch (Exception ex) {  
  58.                 dispatchException = ex;  
  59.             }  
  60. //重点3:这里执行interceptor的afterCompletion方法  
  61.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  62.         }  
  63. //重点4:当出现异常时,仍然执行afterCompletion方法  
  64.         catch (Exception ex) {  
  65.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
  66.         }  
  67.         catch (Error err) {  
  68.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
  69.         }  
  70.         finally {  
  71.             if (asyncManager.isConcurrentHandlingStarted()) {  
  72.                 // Instead of postHandle and afterCompletion  
  73.                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
  74.                 return;  
  75.             }  
  76.             // Clean up any resources used by a multipart request.  
  77.             if (multipartRequestParsed) {  
  78.                 cleanupMultipart(processedRequest);  
  79.             }  
  80.         }  
  81.     }  

先看重点1:  
Java代码   收藏代码
  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.         if (getInterceptors() != null) {  
  3.             for (int i = 0; i < getInterceptors().length; i++) {  
  4.                 HandlerInterceptor interceptor = getInterceptors()[i];  
  5.                 if (!interceptor.preHandle(request, response, this.handler)) {  
  6.                     triggerAfterCompletion(request, response, null);  
  7.                     return false;  
  8.                 }  
  9.                 this.interceptorIndex = i;  
  10.             }  
  11.         }  
  12.         return true;  
  13.     }  

执行preHandle方法,一旦有一个preHandle返回false,则触发triggerAfterCompletion:  
Java代码   收藏代码
  1. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)  
  2.             throws Exception {  
  3.   
  4.         if (getInterceptors() == null) {  
  5.             return;  
  6.         }  
  7.         for (int i = this.interceptorIndex; i >= 0; i--) {  
  8.             HandlerInterceptor interceptor = getInterceptors()[i];  
  9.             try {  
  10.                 interceptor.afterCompletion(request, response, this.handler, ex);  
  11.             }  
  12.             catch (Throwable ex2) {  
  13.                 logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);  
  14.             }  
  15.         }  
  16.     }  

看下这里的for循环的条件,从interceptorIndex开始到0,逆序执行interceptor.afterCompletion。 
重点2 postHandle:
 
Java代码   收藏代码
  1. void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {  
  2.         if (getInterceptors() == null) {  
  3.             return;  
  4.         }  
  5.         for (int i = getInterceptors().length - 1; i >= 0; i--) {  
  6.             HandlerInterceptor interceptor = getInterceptors()[i];  
  7.             interceptor.postHandle(request, response, this.handler, mv);  
  8.         }  
  9.     }  

这个没有什么特殊,preHandle只有参数HttpServletRequest和HttpServletResponse,而postHandle则加入了返回结果ModelAndView,我们可以对ModelAndView进行进一步的修改,此时的view(若有)还没有经过渲染。 
重点3 :
 
Java代码   收藏代码
  1. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,  
  2.             HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {  
  3.   
  4.         boolean errorView = false;  
  5.   
  6.         if (exception != null) {  
  7.             if (exception instanceof ModelAndViewDefiningException) {  
  8.                 logger.debug("ModelAndViewDefiningException encountered", exception);  
  9.                 mv = ((ModelAndViewDefiningException) exception).getModelAndView();  
  10.             }  
  11.             else {  
  12.                 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
  13.                 mv = processHandlerException(request, response, handler, exception);  
  14.                 errorView = (mv != null);  
  15.             }  
  16.         }  
  17.   
  18.         // Did the handler return a view to render?  
  19.         if (mv != null && !mv.wasCleared()) {  
  20.             render(mv, request, response);  
  21.             if (errorView) {  
  22.                 WebUtils.clearErrorRequestAttributes(request);  
  23.             }  
  24.         }  
  25.         else {  
  26.             if (logger.isDebugEnabled()) {  
  27.                 logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
  28.                         "': assuming HandlerAdapter completed request handling");  
  29.             }  
  30.         }  
  31.   
  32.         if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
  33.             // Concurrent handling started during a forward  
  34.             return;  
  35.         }  
  36.   
  37.         if (mappedHandler != null) {  
  38.             mappedHandler.triggerAfterCompletion(request, response, null);  
  39.         }  
  40.     }  

这里可以看到,如果有view,则渲染完成之后,才会执行triggerAfterCompletion,同时不再拥有对ModelAndView的处理(已经完成了渲染)。所以我们就可以看到当有view时,afterCompletion和postHandle的明显区别。 
重点4:当执行过程发生异常时,也会执行interceptor的afterCompletion方法。 
这里要做下说明,对于preHandler方法是获取不到处理函数的参数值的,如果想对处理函数的参数值进行拦截处理,则要使用Spring AOP。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值