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方法 如何返回false就直接返回了  下面统统不执行
                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方法做准备
       // 说明:如果索引为1的拦截器的preHandle方法返回的是false,即使索引为2的拦截器的preHandle方法返回的是true,索引为2的拦截器的postHandle等后面所有方法统统不执行
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); } } } }

猜你喜欢

转载自www.cnblogs.com/lxy-java/p/12936334.html
今日推荐