您的位置:首页 > 编程语言 > Java开发

springMVC源码分析--DispatcherServlet请求获取及处理

2017-03-06 17:48 477 查看
在之前的博客 springMVC源码分析--容器初始化(二)DispatcherServlet中我们介绍过DispatcherServlet,是在容器初始化过程中出现的,我们之前也说过DispatcherServlet其实就是一个HttpServlet,其实他是HttpServlet的子类,所以它和普通的HttpServlet有同样的配置:

[html] view
plain copy

 print?





<span style="font-size:14px;"><span style="white-space:pre">    </span><servlet>  

        <servlet-name>springmvc</servlet-name>  

        <servlet-class>  

            org.springframework.web.servlet.DispatcherServlet  

        </servlet-class>  

        <init-param>  

            <param-name>contextConfigLocation</param-name>  

            <param-value>classpath:springmvc-config.xml</param-value>  

        </init-param>  

        <load-on-startup>1</load-on-startup>      

    </servlet>  

  

    <servlet-mapping>  

        <servlet-name>springmvc</servlet-name>  

        <url-pattern>*.action</url-pattern>  

    </servlet-mapping></span>  

仅仅把DispatcherServlet当做一个Servlet的话,上面配置的含义就是这个Servlet会被所有的*.action的请求所调用。

既然DispatcherServlet是一个HttpServlet那么它应该会实现HttpServlet提供的如下方法:

当然这些所有的方法的实现是DispatcherServlet的父类FrameworkServlet中实现的。

当然这些实现方法中的默认实现其实是如下的

FrameworkServlet类中

[java] view
plain copy

 print?





@Override  

    protected final void doPost(HttpServletRequest request, HttpServletResponse response)  

            throws ServletException, IOException {  

  

        processRequest(request, response);  

    }  

[java] view
plain copy

 print?





@Override  

    protected final void doGet(HttpServletRequest request, HttpServletResponse response)  

            throws ServletException, IOException {  

  

        processRequest(request, response);  

    }  

processRequest的实现是在FrameworkServlet中,此方法中最主要的操作就是调用doService方法

[java] view
plain copy

 print?





protected final void processRequest(HttpServletRequest request, HttpServletResponse response)  

            throws ServletException, IOException {  

  

        long startTime = System.currentTimeMillis();  

        Throwable failureCause = null;  

  

        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();  

        LocaleContext localeContext = buildLocaleContext(request);  

  

        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();  

        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);  

  

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  

        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());  

  

        initContextHolders(request, localeContext, requestAttributes);  

  

        try {  

            doService(request, response);  

        }  

        catch (ServletException ex) {  

            failureCause = ex;  

            throw ex;  

        }  

        catch (IOException ex) {  

            failureCause = ex;  

            throw ex;  

        }  

        catch (Throwable ex) {  

            failureCause = ex;  

            throw new NestedServletException("Request processing failed", ex);  

        }  

  

        finally {  

            resetContextHolders(request, previousLocaleContext, previousAttributes);  

            if (requestAttributes != null) {  

                requestAttributes.requestCompleted();  

            }  

  

            if (logger.isDebugEnabled()) {  

                if (failureCause != null) {  

                    this.logger.debug("Could not complete request", failureCause);  

                }  

                else {  

                    if (asyncManager.isConcurrentHandlingStarted()) {  

                        logger.debug("Leaving response open for concurrent processing");  

                    }  

                    else {  

                        this.logger.debug("Successfully completed request");  

                    }  

                }  

            }  

  

            publishRequestHandledEvent(request, response, startTime, failureCause);  

        }  

    }  

doService方法的最终实现是在DispatcherServlet中,这样所有的Http请求(GET、POST、PUT和DELETE等)的最终操作就DispatcherServlet中实现了。

DispatcherServlet中doService的实现如下,对Request设置了一些全局属性,最终接下来的操作是在doDispatcher函数中实现了。

[java] view
plain copy

 print?





//获取请求,设置一些request的参数,然后分发给doDispatch  

    @Override  

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  

        if (logger.isDebugEnabled()) {  

            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  

            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  

                    " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  

        }  

  

        // Keep a snapshot of the request attributes in case of an include,  

        // to be able to restore the original attributes after the include.  

        Map<String, Object> attributesSnapshot = null;  

        if (WebUtils.isIncludeRequest(request)) {  

            attributesSnapshot = new HashMap<String, Object>();  

            Enumeration<?> attrNames = request.getAttributeNames();  

            while (attrNames.hasMoreElements()) {  

                String attrName = (String) attrNames.nextElement();  

                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  

                    attributesSnapshot.put(attrName, request.getAttribute(attrName));  

                }  

            }  

        }  

  

        // Make framework objects available to handlers and view objects.  

        /* 设置web应用上下文**/  

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  

        /* 国际化本地**/  

        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  

        /* 样式**/  

        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  

        //设置样式资源  

        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());  

        //请求刷新时保存属性  

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  

        if (inputFlashMap != null) {  

            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  

        }  

        //Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除  

        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  

        //FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 FlashMap 实体.  

        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  

  

        try {  

            doDispatch(request, response);  

        }  

        finally {  

            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  

                // Restore the original attribute snapshot, in case of an include.  

                if (attributesSnapshot != null) {  

                    restoreAttributesAfterInclude(request, attributesSnapshot);  

                }  

            }  

        }  

    }  

doDispatch函数中完成了对一个请求的所有操作,包含的内容还是比较多的,我们就不做详细分解,接下来我们会一步一步的分析一个请求调用Controller的完整过程。

[java] view
plain copy

 print?





/** 

     *将Handler进行分发,handler会被handlerMapping有序的获得 

     *通过查询servlet安装的HandlerAdapters来获得HandlerAdapters来查找第一个支持handler的类 

     *所有的HTTP的方法都会被这个方法掌控。取决于HandlerAdapters 或者handlers 他们自己去决定哪些方法是可用 

     *@param request current HTTP request 

     *@param response current HTTP response 

     */  

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  

        /* 当前HTTP请求**/  

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

  

                // 获得HandlerExecutionChain,其包含HandlerIntercrptor和HandlerMethod  

                mappedHandler = getHandler(processedRequest);  

                if (mappedHandler == null || mappedHandler.getHandler() == null) {  

                    noHandlerFound(processedRequest, response);  

                    return;  

                }  

  

                  

                //获得HandlerAdapter  

                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  

  

                //获得HTTP请求方法  

                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;  

                    }  

                }  

                //如果有拦截器的话,会执行拦截器的preHandler方法  

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {  

                    return;  

                }  

  

                //返回ModelAndView  

                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

  

                if (asyncManager.isConcurrentHandlingStarted()) {  

                    return;  

                }  

                //当view为空时,,根据request设置默认view  

                applyDefaultViewName(processedRequest, mv);  

                //执行拦截器的postHandle  

                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  

                if (mappedHandler != null) {  

                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  

                }  

            }  

            else {  

                // Clean up any resources used by a multipart request.  

                //删除上传资源  

                if (multipartRequestParsed) {  

                    cleanupMultipart(processedRequest);  

                }  

            }  

        }  

    }  

调用完doDispatch之后就完成了一个请求的访问,其会将渲染后的页面或者数据返回给请求发起者。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: