zoukankan      html  css  js  c++  java
  • 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); } } } }
  • 相关阅读:
    HDU 4024 Dwarven Sniper’s hunting(数学公式 或者是二分)
    二分图最大匹配总结
    HDU 4022 Bombing (STL应用)
    HDU 1847 Good Luck in CET4 Everybody!(组合博弈)
    HDU 1556 Color the ball(树状数组)
    HDU 4023 Game(博弈)
    HDU 1406 完数(水题)
    HDU 4021 24 Puzzle
    Oracle 多表查询优化
    【编程之美】字符串移位包含的问题(续)
  • 原文地址:https://www.cnblogs.com/lxy-java/p/12936334.html
Copyright © 2011-2022 走看看