Spring拦截器过滤器之拦截器详解(二)

回顾

上次讲到了拦截器的实现原理,即运用了AOP思想和责任链设计模式,对发起的请求进行拦截,并做处理。如果你自己也跟着写了demo的话,打断点的时候会发现,当return为true 时,会进入HandlerExecutionChain这个类,这个类是什么呢,我们今天就来研究一下。

HandlerExecutionChain

从字面的意思来看,估计你也会猜到这是个执行链,以下是部分属性。

    private final Object handler; //处理器对象
    
    private HandlerInterceptor[] interceptors; //拦截器数组
    
    private List<HandlerInterceptor> interceptorList; //拦截器列表

显然这个类是由处理器对象和若干个拦截器组成的,组合使用就是责任链模式的一个实现。接着看几个主要的方法:

 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;
    }

    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);
                }
            }
        }

    }

详解:你会发现applyPreHandle()这个方法其实就是做着这样一个工作:按照列表中interceptor的顺序来执行它们的preHandle方法,直到有一个返回false。当返回false时,这时会调用triggerAfterCompletion方法,在这个方法中,this.interceptorIndex指向上一个返回true的interceptor的位置,所以在for循环中它会按逆序执行所有返回true的interceptor的afterCompletion方法。换言之,也就是对于任意的返回false的interceptor都不会执行afterCompletion方法。而且是中断之前所有的preHandle执行完成之后才会执行afterCompletion方法,如果你看过LZ之前的文章,那么此时正好解释了为什么说HandlerInterceptor接口中的afterCompletion()方法,先声明的Interceptor的afterCompletion方法后执行的原因!
接下来再看:

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);
            }
        }

    }

详解:这个方法很简单,就是逆序执行所有interceptor的postHandle方法。
最后的triggerAfterCompletion()也是一样,就是从最后一次preHandle成功的interceptor处逆序执行afterCompletion,同样也解释了LZ上文说的postHandle 方法被调用的方向跟preHandle 是相反的,先声明的Interceptor 的postHandle 方法反而会后执行的原因!

HandlerMapping接口

其实,HandlerExecutionChain是通过HandlerMapping的getHandler方法返回的。可能会有点懵,HandlerMapping又是什么鬼?看一张图
springMVC执行流程示意图
上篇文章也说到了,拦截器是在controller之上的非系统级别,现在回头看一下springMVC执行流程,也就清楚了HandlerMapping是做什么的,来看一下代码:

HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;

这个接口中只有这样一个方法,根据函数名,参数及返回值我们不难猜出这个接口的作用,就是根据request返回HandlerExecutionChain。至于HandlerMapping在springMVC中有多种实现,我们此处就不深究了。
对于getHandler最后的调度部分便是springMVC的最外层DispatcherServlet类了

DispatcherServlet类

DispatcherServlet类中调用HandlerMapping的getHandler的方法为getHandler(同名)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping hm : this.handlerMappings) {
         if (logger.isTraceEnabled()) {
            logger.trace(
                  "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
         }
         HandlerExecutionChain handler = hm.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

从代码中不难看出整个逻辑就是依次判断servlet中的每个handlerMapping是否能够匹配该请求,直到找到那个匹配的然后返回处理结果。
对于HandlerExecutionChain的调用我们可以在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 (logger.isDebugEnabled()) {
               logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
            }
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }

         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

         applyDefaultViewName(processedRequest, mv);
         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);
      }
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      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);
         }
      }
   }
}
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.isDebugEnabled()) {
         logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
               "': assuming HandlerAdapter completed request handling");
      }
   }

   if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      // Concurrent handling started during a forward
      return;
   }

   if (mappedHandler != null) {
      mappedHandler.triggerAfterCompletion(request, response, null);
   }
}

从上面代码中我们可以验证前面所说的HandlerInterceptor接口中三个方法的执行顺序:
preHandle是在找到处理handler对象的HandlerMapping之后,HandlerAdapter调度handler之前执行。
postHandle是在HandlerAdapter调度handler之后,DispatcherServlet渲染视图之前执行。
afterCompletion是在渲染视图结束后执行。

总结

引用道友的总结,即:
那么整个拦截器的处理过程我们便可以很清晰地分为两种情况,一种是所有拦截器preHandle都返回true的情况,另一种是有拦截器preHandle返回false的情况。

我们先假设我们有三个拦截器A,B,C,D。

对于第一种情况,那么在DispatcherServlet中分别依次调用HandlerExecutionChain类中applyPreHandle、applyPostHandle和triggerAfterCompletion方法,

那么所有方法的执行顺序为

A.pre -> B.pre -> C.pre -> D.pre

-> D.post -> C.post -> B.post -> A.post

-> D.after -> C.after -> B.after -> A.after

对于第二种情况,我们不妨设C拦截器的preHandle返回为false。

这时DispatcherServlet类调用HandlerExecutionChain类中applyPreHandle方法,然后由applyPreHandle调用triggerAfterCompletion方法,

那么执行情况如下

A.pre -> B.pre -> C.pre

-> B.after -> A.after

下回讲解过滤器!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值