SpringMVC中的拦截器Interceptor

一、过滤器与拦截器的区别

  • 过滤器

  • 过滤器是Tomcat中的组件

  • 过滤器是过滤Servlet请求的

  • 过滤的执行时机

  • 1)Servlet执行之前

  • 2)Servlet执行之后

  • 拦截器

  • 拦截器是SpringMVC中的组件

  • 拦截器是拦截Controller请求的

  • 拦截器的执行时机

  • 1)在DispatcherServlet执行之后,Controller执行之前执行

  • 2)在Controller执行之后,DispatcherServlet执行之前执行

  • 3)在DispatcherServlet执行之后,视图渲染完成之后执行

  • 图解

二、自定义拦截器

  • 实现HandlerInterceptor接口(推荐使用),并实现其中的三个方法。

  • 继承HandlerInterceprotAdapter适配器类(不推荐)

  • 在SpringMVC中装配拦截器,通过<mvc:interceptors/>标签

拦截器1

public class MyInterceptor implements HandlerInterceptor {

    /**
     * 该方法在DispatcherServlet执行之后,Controller执行之前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor --> preHandler()!");
        return true;
    }

    /**
     * 该方法在Controller执行之后,DispatcherServlet执行之前执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor --> postHandle()!");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 该方法在DispatcherServlet渲染视图之后,执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor --> afterCompletion()!");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

拦截器2

public class MyInterceptor2 implements HandlerInterceptor {

    /**
     * 该方法在DispatcherServlet执行之后,Controller执行之前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor222 --> preHandler()!");
        return true;
    }

    /**
     * 该方法在Controller执行之后,DispatcherServlet执行之前执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor222 --> postHandle()!");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 该方法在DispatcherServlet渲染视图之后,执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor222 --> afterCompletion()!");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

装配拦截器

<!-- 配置全局拦截器 -->
<mvc:interceptors>
    <!-- 拦截器的执行顺序以声明的顺序来决定 -->
    <bean id="myInterceptor" class="it.demo.interceptor.MyInterceptor"/>
    <bean id="myInterceptor1" class="it.demo.interceptor.MyInterceptor1"/>
</mvc:interceptors>

三、HandlerInterceptor中的方法

3.1、preHandle()

这个方法在Controller方法执行之前执行,在该方法中可以做一些权限校验的操作。如果希望该拦截器对请求进行拦截后,还要调用其他的拦截器或者控制器去处理业务,则返回true;如果希望该拦截器拦截请求后,不需要再调用其他拦截器或控制器去处理业务,则返回false。

3.2、postHandle()

这个方法在 Controller 方法执行之后,渲染视图之前执行,可以对Controller方法的返回值进行处理。

3.3、afterCompletion()方法

这个方法在 Controller方法执行之后,视图渲染完毕之后执行,也即DispatcherServlet完全处理完请求之后执行,可以做一些资源清理的操作。

四、拦截器的工作原理

4.1、单个拦截器的执行顺序

  • 服务器接收到浏览器发出的请求

  • 执行拦截器的preHandle()方法

  • 执行Controller处理请求

  • 执行拦截器的postHandle()方法

  • DispatcherServlet渲染视图

  • 执行拦截器的afterCompletion()方法

myFilter---执行Servlet之前...
MyInterceptor --> preHandler()!
==>处理JSON
MyInterceptor --> postHandle()!
MyInterceptor --> afterCompletion()!
myFilter---执行Servlet之后...

4.2、多个拦截器的执行顺序

图解:

  • 服务器接收到浏览器发出的请求

  • 执行第一个拦截器的preHandle()方法

  • 执行第二个拦截器的preHandle()方法

  • 调用Controller处理请求

  • 执行第二个拦截器的postHandle()方法

  • 执行第一个拦截器的postHandle()方法

  • DispatcherServlet渲染视图

  • 执行第二个拦截器的afterCompletion()方法

  • 执行第一个拦截器的afterCompletion()方法

myFilter---执行Servlet之前...
MyInterceptor --> preHandler()!
MyInterceptor222 --> preHandler()!
==>处理JSON
MyInterceptor222 --> postHandle()!
MyInterceptor --> postHandle()!
MyInterceptor222 --> afterCompletion()!
MyInterceptor --> afterCompletion()!
myFilter---执行Servlet之后...

4.3、preHandle()返回值问题

4.3.1、第一个拦截器preHandle()方法返回false

将第一个拦截器的preHandle()返回值改为false,第二个拦截器的preHandle()返回值为true,查看执行顺序。

public class MyInterceptor implements HandlerInterceptor {

    /**
     * 该方法在DispatcherServlet执行之后,Controller执行之前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor --> preHandler()!");
        return false;
    }

    /**
     * 该方法在Controller执行之后,DispatcherServlet执行之前执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor --> postHandle()!");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 该方法在DispatcherServlet渲染视图之后,执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor --> afterCompletion()!");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

执行顺序:

myFilter---执行Servlet之前...
MyInterceptor --> preHandler()!
myFilter---执行Servlet之后...

4.3.2、第二个拦截器preHandle()方法返回false

将第一个拦截器的preHandle()方法的返回值改为true,第二个拦截器的preHandle()方法的返回值改为false,查看执行顺序。

public class MyInterceptor2 implements HandlerInterceptor {

    /**
     * 该方法在DispatcherServlet执行之后,Controller执行之前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor222 --> preHandler()!");
        return false;
    }

    /**
     * 该方法在Controller执行之后,DispatcherServlet执行之前执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor222 --> postHandle()!");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 该方法在DispatcherServlet渲染视图之后,执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor222 --> afterCompletion()!");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

执行顺序:

myFilter---执行Servlet之前...
MyInterceptor --> preHandler()!
MyInterceptor222 --> preHandler()!
MyInterceptor --> afterCompletion()!
myFilter---执行Servlet之后...

4.3.2、小结

  • 当第一个拦截器的preHandle()方法返回false时,不会继续执行,请求结束。

  • 当第一个拦截器的preHandle()方法返回true,第二个拦截器的preHandle()方法返回false时,会执行第一个拦截器和第二个拦截器的preHandle(),以及第一个拦截器的afterCompletion()方法,之后请求结束。

  • 当前拦截器的preHandle()方法返回false,会执行之前拦截器的preHandle()当前拦截器的preHandle(),以及之前拦截器的afterCompletion()

4.4、拦截器底层源码

4.4.1、拦截器的执行顺序

SpringMVC接收到请求之后,会调用DispatcherServlet中的doDispatch()方法处理请求,doDispatch()方法中会在Controller处理请求之前调用拦截器的preHandle()方法Controller处理完请求之后调用拦截器的postHandle()方法,以及视图渲染完毕之后调用拦截器的afterCompletion()方法

a)DispatcherServlet的doDispatch()方法

源码如下:

// 调用DispatcherServlet中的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;
            }

            // 这里调用Controller处理请求
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            applyDefaultViewName(processedRequest, mv);
            // 这里调用拦截器中的postHandle()方法
            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);
        }
        // 处理ModelAndView
        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);
            }
        }
    }
}

b)processDispatchResult()方法

源码如下:

// dispatcherServlet中的doDispatch()通过Controller处理完成请求之后,调用该方法解析视图
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;
    }

    if (mappedHandler != null) {
        // 视图解析完成之后,调用拦截器的afterCompletion()方法
        // Exception (if any) is already handled..
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

c)applyPreHandle方法

源码如下:

// 在这个方法中,通过for循环的方式调用每一个拦截器的preHandle()方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 这里的this.interceptorList就是我们装配的拦截器
    // 从0开始按照装配的顺序,也就是正序的方式依次调用拦截器的preHandle()方法
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 调用preHandle()方法
        if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }
        // this.interceptorIndex初始值为-1,每调用一个preHandle()方法并且返回值为true时,会将i赋值给interceptorIndex
        // 先记住这个参数,后面有用!!!
        this.interceptorIndex = i;
    }
    return true;
}

d)applyPostHandle方法
// 在这个方法中会通过for循环的方式调用每一个拦截器的postHandle()方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
    // 这里的this.interceptorList就是装配的拦截器
    // 按照倒序的方式,依次调用拦截器的postHandle()方法
    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
          // 调用拦截器的postHandle()方法
          interceptor.postHandle(request, response, this.handler, mv);
    }
}

e)triggerAfterCompletion方法
// 在这个方法中,依次调用拦截器的afterCompletion()方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // 这里循环 interceptorIndex + 1 次,先记住这里,后面有用!!!
    for (int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            // 调用拦截器的afterCompletion()方法
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
        catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}

4.4.2、preHandle()方法返回值问题

配置一个拦截器,如果拦截器的preHandle()返回false,请求结束,不会继续执行。

配置多个拦截器,如果第一个拦截器的preHandle()返回false,请求结束,不会继续执行。

配置多个拦截器,并非第一个拦截器的preHandle()返回false,而是第二个拦截器的preHandle()返回false时,会执行第二个拦截器的preHandle()方法、第一个拦截器的preHandle()方法以及第一个拦截器的afterCompletion()方法。

为什么会这样?我们通过源码的方式来理解。

a)第一个拦截器的preHandle()返回false

DispatcherServlet中doDispatch()方法,调用拦截器的preHandle()方法

// 调用DispatcherServlet中的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()方法
            // applyPreHandle方法会调用拦截器的preHandle()方法
            // 如果applyPreHandle()方法返回false,会直接结束doDispatch()方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                // applyPreHandle()方法返回false,结束当前方法
                return;
            }

            // 这里调用Controller处理请求
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            applyDefaultViewName(processedRequest, mv);
            // 这里调用拦截器中的postHandle()方法
            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);
        }
        // 处理ModelAndView
        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);
            }
        }
    }
}

applyPreHandle()方法

// 这个方法按照拦截器定义的顺序,依次调用拦截器中的preHandle()方法
// 这里要注意this.interceptorIndex,默认值为-1
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 从0开始,正序遍历    
    for (int i = 0; i < this.interceptorList.size(); i++) {
        // 第一次循环,i为0,获取到的是第一个拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行第一个拦截器的preHandle()方法,返回值为false
         if (!interceptor.preHandle(request, response, this.handler)) {
            // 对false取反,进入到if语句块中,接着调用triggerAfterCompletion()方法
            // preHandle()方法返回false,没有为interceptorIndex赋值,此时interceptorIndex为-1
            triggerAfterCompletion(request, response, null);
            return false;
        }
        // 注意:只有preHandle()方法返回值为true时,才会为interceptorIndex赋值!!!
        this.interceptorIndex = i;
    }
    return true;
}

triggerAfterCompletion()方法

// 在这个方法中,调用拦截器的afterCompletion()方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // applyPreHandle方法中,调用第一个拦截器的preHandle()方法返回false,没有为interceptorIndex赋值,此时interceptorIndex为-1
    // i为-1,不会执行for循环,也即并不会执行第一个、第二个拦截器的afterCompletion()方法
    for (int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            interceptor.afterCompletion(request, response, this.handler, ex);
         }
         catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}

applyPreHandle()方法调用完成triggerAfterCompletion()方法后,返回false,回到DispatcherServlet的doDispatch()方法中:

// applyPreQHandle()方法返回false,对false取反,进入if语句块,doDispatche()方法结束
// 不会继续调用Controller处理请求,也即请求结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    // applyPreHandle()方法返回false,结束当前方法
    return;
}

通过分析上述源码,可以知道:第一个拦截器的preHandle()方法返回false后,请求结束,不会继续执行。

b)第二个拦截器的preHandle()返回false

DispatcherServlet中doDispatch()方法,调用拦截器的preHandle()方法

// 调用DispatcherServlet中的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()方法
            // applyPreHandle方法会调用拦截器的preHandle()方法
            // 如果applyPreHandle()方法返回false,会直接结束doDispatch()方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                // applyPreHandle()方法返回false,结束当前方法
                return;
            }

            // 这里调用Controller处理请求
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            applyDefaultViewName(processedRequest, mv);
            // 这里调用拦截器中的postHandle()方法
            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);
        }
        // 处理ModelAndView
        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);
            }
        }
    }
}

applyPreHandle()方法

第一次for循环,调用第一个拦截器的preHandle()方法

// 这个方法按照拦截器定义的顺序,依次调用拦截器中的preHandle()方法
// 这里要注意this.interceptorIndex,默认值为-1
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 从0开始,正序遍历    
    for (int i = 0; i < this.interceptorList.size(); i++) {
        // 第一次循环,i为0,获取到的是第一个拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行第一个拦截器的preHandle()方法,返回值为true,不会进入if语句块,继续执行
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }

        // 注意:只有preHandle()方法返回值为true时,才会为interceptorIndex赋值
        // 第一个拦截器的preHandle()方法返回true,不会进入if语句块
        // 将i赋值给interceptorIndex,此时interceptorIndex为0
        this.interceptorIndex = i;
    }
    return true;
}

第二次for循环,调用第二个拦截器的preHandle()方法

// 这个方法按照拦截器定义的顺序,依次调用拦截器中的preHandle()方法
// 这里要注意this.interceptorIndex,默认值为-1
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 第二次循环,此时i为1
    for (int i = 0; i < this.interceptorList.size(); i++) {
        // 第二次循环,i为1,获取到的是第二个拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行第二个拦截器的preHandle()方法,返回值为false,进入if代码块
         if (!interceptor.preHandle(request, response, this.handler)) {
            // 注意,此时interceptorIndex为0
            // 调用拦截器的afterCompletion()方法
            triggerAfterCompletion(request, response, null);
            return false;
        }

        // 注意:只有preHandle()方法返回值为true时,才会为interceptorIndex赋值
        // 由于第二个拦截器的preHandle()方法返回false,不会执行到这里
        this.interceptorIndex = i;
    }
    return true;
}

triggerAfterCompletion()方法

// 这个方法中会调用拦截器的afterCompletion()方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // 注意,此时interceptorIndex为0,意味着for循环只循环一次,也即只会执行第一个拦截器的afterCompletion()方法
    for (int i = this.interceptorIndex; i >= 0; i--) {
        // 按照拦截器定义的顺序,获取到第一个拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            // 调用第一个拦截器的afterCompletion()方法
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
        catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
         }
    }
}

triggerAfterCompletion()执行完成之后,applyPreHandle()方法返回false,回到了DispatcherServlet的doDispatch()方法:

// applyPreQHandle()方法返回false,对false取反,进入if语句块,doDispatche()方法结束
// 不会继续调用Controller处理请求,也即请求结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    // applyPreHandle()方法返回false,结束当前方法
    return;
}

通过分析上述源码,可以知道:第一个拦截器的preHandle()方法返回true,第二个拦截器的preHandle()方法返回false后,会执行第一个拦截器的preHandle()方法、第二个拦截器的preHandle()方法,以及第一个拦截器的afterCompletion()方法

五、总结

1、拦截器和过滤器的区别

  • 拦截器

  • 拦截器是SpringMVC中的组件

  • 拦截器是用来拦截Controller请求的

  • 拦截器的执行时机有三处:

  • 1、执行DispatcherServlet之后,在执行Controller之前执行。

  • 2、执行Controller之后,在执行DispatcherServlet之前执行。

  • 3、在DispatcherServlet渲染视图之后执行

  • 过滤器

  • 过滤器是Tomcat中的组件

  • 过滤器是用来过滤Servlet请求的

  • 过滤器的执行时机有两处:

  • 1、Servlet执行之前

  • 2、Servlet执行之后

2、拦截器的执行顺序是按照XML文件中定义的顺序决定的。

3、拦截器的执行顺序

  • 定义一个拦截器

拦截器的preHandle()方法
调用Controller处理请求
拦截器的postHandle()方法
拦截器的afterCompletion()方法
  • 定义多个拦截器

第一个拦截器的preHandle()方法
第二个拦截器的preHandle()方法
调用Controller处理请求
第二个拦截器的postHandle()方法
第一个拦截器的postHandle()方法
第二个拦截器的afterCompletion()方法
第一个拦截器的afterCompletion()方法

4、只有当拦截器的preHandle()方法返回true时,才会执行后面的postHandle()以及afterCompletion()方法。

5.定义多个拦截器

  • 当第一个拦截器的preHandle()返回false时,不会继续向下执行,请求终止。

  • 当并非第一个拦截器的 preHandle()返回false,而是第二个拦截器的preHandle()返回时,会执行第二个拦截器的preHandle()、第一个拦截器的preHandle()以及第一个拦截器的afterCompletion()方法。

如有不足之处,请在评论区中指出。一起努力,共勉!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值