• SpringMvc拦截器运行原理。


    首先,先简单的说一下怎么配置SpringMvc的拦截器。

    分两步,第一步先定义一个类,实现HandlerInterceptor接口。

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    public class TestInterceptor implements HandlerInterceptor{
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("preHandle invoke");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle invoke");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println("afterCompletion invoke");
            
        }
    
    }

    第二布,配置springMvc.xml

    <!-- 拦截器 -->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/*"/>
                <bean class="com.mmc.interceptor.TestInterceptor"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

    完工。下面分析原理

    打开这个DispatcherServlet类,这个类是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 || mappedHandler.getHandler() == 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()) {
                            String requestUri = urlPathHelper.getRequestUri(request);
                            logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                        }
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
    
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
    
                    try {
                        // Actually invoke the handler.
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    }
                    finally {
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
                    }
    
                    applyDefaultViewName(request, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            }
            catch (Error err) {
                triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
            }
            finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    // Instead of postHandle and afterCompletion
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    return;
                }
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }

    里面我标红了四处,第一处对应执行自定义拦截器的preHandler方法,第二处对应执行你的Controller类中的RequestMapping映射的处理方法,第三处是自定义拦截器的postHandle方法,第四处是自定义拦截器的afterCompletion方法。


    这些可能很多人都知道,但是我们肯定还有疑问,为什么他能调用到我的拦截器里写的方法呢?

     接着往下分析。


    于是我们点开我第一处标红那里的mappedHandler.applyPreHandle方法。代码如下:

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (getInterceptors() != null) {
                for (int i = 0; i < getInterceptors().length; i++) {
                    HandlerInterceptor interceptor = getInterceptors()[i];
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        triggerAfterCompletion(request, response, null);
                        return false;
                    }
                    this.interceptorIndex = i;
                }
            }
            return true;
        }

    看得出来,他是在遍历getInterceptors(),所以在点开这个方法。

    public HandlerInterceptor[] getInterceptors() {
            if (this.interceptors == null && this.interceptorList != null) {
                this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
            }
            return this.interceptors;
        }
    View Code

    这里面有两个变量,interceptorList和interceptors。这时我肯定会猜想,肯定是某个时候系统框架把这两个变量赋值了,然后在我执行方法的时候都会去看看这两个变量是不是有值的。有就执行拦截器。

    那么这两个变量是什么时候赋值的呢?找到定义这两个变量的地方,他们是在HandlerExecutionChain类里面,我把断点打在这个变量定义那里。debug运行,代码停在了HandlerExecutionChain里面

     看debug模式中的方法执行顺序,点到doDispatch方法里面,在执行applyPreHandle即调用拦截器的方法之前,有一个getHandler方法,这个方法里面有getHandlerExecutionChain方法。这个方法里面有如下代码:

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
            HandlerExecutionChain chain =
                (handler instanceof HandlerExecutionChain) ?
                    (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
    
            chain.addInterceptors(getAdaptedInterceptors());
    
            String lookupPath = urlPathHelper.getLookupPathForRequest(request);
            for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
                if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
    
            return chain;
        }

    注意看,里面有一句chain.addInterceptor(mappedInterceptor.getInterceptor());这个从名字就知道是添加拦截器。而这个拦截器是从mappedInterceptor获得的属性,mappedInterceptor是遍历mappedInterceptors得到的。而这个对象在我运行这个的时候就已经存在了。所以我思考是不是启动项目的时候就已经初始化了,而且是根据我的xml配置文件来初始化的。于是我在mappedInterceptors对象处打断点,启动tomcat。果然代码执行到了。在AbstractHandlerMapping类中找到了这个方法,

    @Override
        protected void initApplicationContext() throws BeansException {
            extendInterceptors(this.interceptors);
            detectMappedInterceptors(this.mappedInterceptors);
            initInterceptors();
     

     在这个detectMappedInterceptors(this.mappedInterceptors);里面便是将mappedInterceptors对象赋值了。下面我就不贴代码了。就是去找MappedInterceptor类,这个类是根据xml文件中<mvc:interceptor>的内容来构建的。构建方法在InterceptorsBeanDefinitionParser类里面。

    顺着来一遍就是这样的:

     启动项目,InterceptorsBeanDefinitionParser类会根据配置文件构建MappedInterceptor对象集合,当我发送请求的时候,系统去看这个集合里有没有值,如果有值,就遍历执行这个对象,取得这个对象中的HandlerInterceptor属性,也就是我自定义的拦截器的对象。然后去执行我这个拦截器中的三个方法。到此拦截器的运行原理就分析完了。

    有分析不对的地方请不吝指出

    
    
    
    
    
  • 相关阅读:
    数组是个好东西
    排列(permutation) 用1,2,3,…,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要 求abc:def:ghi=1:2:3。按照“abc def ghi”的格式输出所有解,每行一个解。
    子序列的和
    韩信点兵
    水仙花数
    阶乘之和
    3n+1问题
    MongoDB 安装
    mysql中bigint在php中表示
    Android之NDK开发
  • 原文地址:https://www.cnblogs.com/javammc/p/8566664.html
Copyright © 2020-2023  润新知