• DispatcherServlet源码分析


    一、客户端发送请求的总体过程

      DispatcherServlet是SpringMVC的入口,DispatcherServlet其实也是一个Servlet。服务器处理客户端请求的步骤如下:

      1、客户端发送请求的时候,会调用Servlet对应的doGet、doPost、doDelete等方法。

      2、上面的方法会调用processRequest方法

      3、processRequest方法进一步调用doService方法

      4、DispatcherServlet实现了doService方法,在doService方法中对Request参数进行处理,然后调用doDispatch方法

      5、在doDispatch方法中获取并调用处理器映射器、处理器适配器,获取并返回执行结果。

      DispatcherServlet是Web中处于比较核心的位置,被称为前端控制器。SpringMVC中常用的几个概念,处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)和视图解析器(ViewResolver)都在DispatcherServlet的doDispatch中有所体现。

      通过调用getHandler方法获取Handler对象,getHandler方法会调用HandlerMapping,通过请求的路径查找Handler;返回值是一个HandlerExecutionChain对象,其中不只包含了Handler对象,还包含一个HandlerInterceptor(拦截器)的链表。

      Handler需要借助于HandlerAdapter来执行,doDispatch调用getHandlerAdapter方法查找具体的HandlerAdapter。Spring容器中可能配置了多个HandlerAdapter,具体哪个HandlerAdapter能够处理当前的Handler,是根据HandlerAdapter的supports方法来查找可以处理该Handler的HandlerAdapter。

      之后会调用拦截器的preHandler方法,HandlerAdapter会处理具体的Handler,调用拦截器的postHandler方法。

      然后,doDispatch会调用processDispatchResult方法,在processDispatchResult方法中,在其中的render方法中,会循环ViewResolver,确定哪个ViewResolver可以解析对应view,然后调用view的render方法进行渲染。processDispatchResult方法还会调用拦截器的afterCompletion方法。

      

    二、处理器映射器

       通过调用处理器映射器,得到请求路径对应的处理器。如果没有找到处理器,则在Response中返回错误信息,该方法直接退出。

        // Determine handler for the current request.
        mappedHandler = getHandler(processedRequest, false);
        if (mappedHandler == null || mappedHandler.getHandler() == null) {
            noHandlerFound(processedRequest, response);
            return;
        }

      getHandler方法的代码如下,实质就是循环便利所有处理器映射器,找到与请求路径相匹配的处理器映射器。

        /**
         * Return the HandlerExecutionChain for this request.
         * <p>Tries all handler mappings in order.
         * @param request current HTTP request
         * @return the HandlerExecutionChain, or {@code null} if no handler could be found
         */
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            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;
        }

    三、判断是否网页是否需要重新生成

      HTTP协议允许只发送带有Last-Modified的表头信息到服务器端,服务器端判断本地的信息是否修改了,如果没修改,最后的时间将与Last-Modified一致,此时不需要服务器端再生成信息,直接告诉浏览器信息没有改变,使用其本地数据即可。

      Last-Modified介绍

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

    四、拦截器

      在从处理器映射器获取对应的处理器的时候(通过DispatcherServlet的getHandler方法),返回的不是处理器对象,而是一个HandlerExecutionChain,这个HandlerExecutionChain中包含Handler对象;同时还包含一个HandlerInterceptor链表,而HandlerInterceptor就是拦截器。

      而对于HandlerInterceptor接口中定义的三个方法中,preHandler在handler的执行前被调用;而postHandler在handler执行后,在进行视图解析之前执行;afterCompletion在view渲染完成、在DispatcherServlet返回之前执行。 

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

      上面的代码中,mappedHandler.applyPreHandle(processedRequest, response)是执行拦截器的preHandler;而mappedHandler.applyPostHandle(processedRequest, response, mv)则执行拦截器的postHandler方法。而拦截器的afterCompletion方法则是在processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)方法中执行的,位置是在该方法的最后,view渲染完成后。

    PS:我们需要注意的是:当preHandler返回false时,当前的请求将在执行完afterCompletion后直接返回,handler也将不会执行。源码如下:

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

       需要注意的是上面的interceptorIndex变量,它保存的是刚刚已经执行过的拦截器。而一旦拦截器的preHandler返回false,就会进入triggerAfterCompletion方法,该方法会执行拦截器的afterCompletion方法。但是不可能把所有拦截器的afterCompletion方法都执行一遍,所以使用interceptorIndex进行记录,就可以很方便的知道都有哪些拦截器执行了preHandler方法,调用他们的afterCompletion就可以了。

      另外需要注意的地方是,设置interceptorIndex的位置是在循环的最后,也就是说,此处记录的是preHandler返回true的那个拦截器对应的index,也就是说返回false的拦截器的afterCompletion方法不会被调用。

    五、处理器适配器

      通过HandlerExecutionChain.getHandler返回处理器对象,getHandler返回的是Object对象。DispatcherServlet通过getHandlerAdapter方法找到与Handler匹配的HandlerAdapter类,再通过这个HandlerAdapter去执行Handler对应的方法。

    获取Handler匹配的HandlerAdapter:

      protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            for (HandlerAdapter ha : this.handlerAdapters) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing handler adapter [" + ha + "]");
                }
                if (ha.supports(handler)) {
                    return ha;
                }
            }
            throw new ServletException("No adapter for handler [" + handler +
                    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
        }

    HandlerAdapter去执行Handler对应方法,其中返回的mv是ModelAndView对象:

        try {
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
        }

    六、视图解析器

      DispatcherServlet在processDispatchResult中解析并返回View,在render方法中会根据ModelAndView渲染产生View对象。

  • 相关阅读:
    R 误差自相关与DW检验
    R WLS矫正方差非齐《回归分析与线性统计模型》page115
    R 再也不用愁变量太多跑回归太麻烦!R语言循环常用方法总结
    R 读取回归模型的信息
    R 创建一个空的数据框
    R 《回归分析与线性统计模型》page93.6
    自编函数
    ntpdate 正确的做法
    利用yum升级Centos6的gcc版本,使其支持C++11
    Python Shell 中敲击方向键显示「^[[C^[[D],问题解决
  • 原文地址:https://www.cnblogs.com/huanyou/p/6699022.html
Copyright © 2020-2023  润新知