天天看點

SpringMVC源碼解析從service到doDispatch(上))HttpServlet#serviceFrameworkServlet#service

請求在被Servlet處理之前會先被過濾器處理,之後調用Servlet的service方法來對相應的請求進行處理響應。是以我們這裡分析的入口是Servlet的service方法。

我們在用SpringMVC的時候,通常都會在web.xml中進行這樣的配置:

<servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:learn-spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>      

所有的請求(除靜态資源)将由DispatcherServlet處理。

SpringMVC源碼解析從service到doDispatch(上))HttpServlet#serviceFrameworkServlet#service

DispatcherServlet繼承了FrameworkServlet,FrameworkServlet繼承了HttpServletBean,HttpServletBean繼承了HttpServlet,HttpServlet繼承了GenericServlet,GenericServlet則實作了我們最頂級的接口Servlet和ServletConfig。

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(DEFAULT_STRATEGIES_PREFIX)) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        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));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new 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);
                }
            }
        }
    }      

從DispatcherServlet的源碼中我們沒有找到service(ServletRequest req, ServletResponse res)這個方法,但是我們在DispatcherServlet的父類HttpServlet中找到了這個方法,我們去HttpServlet中看看這個方法的内容:

HttpServlet#service

SpringMVC源碼解析從service到doDispatch(上))HttpServlet#serviceFrameworkServlet#service

将ServletRequest和ServletResponse轉換為HttpServletRequest和HttpServletResponse

因為web開發,用HTTP協定,是以需要HttpServletRequest和HttpServletResponse

接下來就是調用service(HttpServletRequest request, HttpServletResponse response),

HttpServlet和FrameworkServlet中都找到了這個方法,但是HttpServlet是FrameworkServlet的父類,即FrameworkServlet中重寫了service這個方法,是以我們這裡取FrameworkServlet中去看看這個方法的内容:

FrameworkServlet#service

SpringMVC源碼解析從service到doDispatch(上))HttpServlet#serviceFrameworkServlet#service

根據請求的方法類型轉換對應的枚舉類

HttpMethod這個定義了這樣的幾種枚舉類型:GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;而這些也是RFC标準中幾種請求類型。如果請求類型為PATCH或者沒有找到相應的請求類型的話,則直接調用processRequest這個方法。但是這種情況我們很少很少會遇到。

是以這裡會執行super.service這個方法。即調用HttpServlet中的service方法。我們看一下HttpServlet中這個service方法的内容:

繼續閱讀