1. 程式人生 > >Spring MVC請求處理流程分析

Spring MVC請求處理流程分析

一、簡介

Spring MVC框架在工作中經常用到,配置簡單,使用起來也很方便,很多書籍和部落格都有介紹其處理流程,但是,對於其原理,總是似懂非懂的樣子。我們做技術,需要做到知其然,還要知其所以然。今天我們結合原始碼來深入瞭解一下Spring MVC的處理流程。

以上流程圖是Spring MVC的處理流程(參考:spring-mvc-flow-with-example),原作者對流程的解釋如下:

Step 1: First request will be received by DispatcherServlet.

Step 2: DispatcherServlet will take the help of HandlerMapping and get to know the Controller class name associated with the given request.

Step 3: So request transfer to the Controller, and then controller will process the request by executing appropriate methods and returns ModelAndView object (contains Model data and View name) back to the DispatcherServlet.

Step 4: Now DispatcherServlet send the model object to the ViewResolver to get the actual view page.

Step 5: Finally DispatcherServlet will pass the Model object to the View page to display the result.

針對以上流程,這裡需要更加詳細一點:

1、請求被web 容器接收,並且根據contextPath將請求傳送給DispatcherServlet

2、DispatcherServlet接收到請求後,會設定一些屬性(localeResolver、themeResolver等等),在根據request在handlerMappings中查詢對應的HandlerExecutionChain;然後根據HandlerExecutionChain中的handler來找到HandlerAdapter,然後通過反射來呼叫handler中的對應方法(RequestMapping對應的方法)

3、handler就是對應的controller,呼叫controller中的對應方法來進行業務邏輯處理,返回ModelAndView(或者邏輯檢視名稱)

4、ViewResolver根據邏輯檢視名稱、檢視前後綴,來獲取實際的邏輯檢視

5、獲取實際檢視之後,就會使用model來渲染檢視,得到使用者實際看到的檢視,然後返回給客戶端。

二、Demo樣例

我們執行一個小樣例(github地址:https://github.com/yangjianzhou/spring-mvc-demo)來了解Spring MVC處理流程,專案結構如下:

web.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>smart</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>smart</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

smart-servlet.xml的內容如下:

 <context:component-scan base-package="com.iwill.mvc"/>

    <!-- 在使用Excel PDF的檢視時,請先把這個檢視解析器註釋掉,否則產生檢視解析問題-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:order="100" p:viewClass="org.springframework.web.servlet.view.JstlView"
          p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>

UserController.java的程式碼如下:

package com.iwill.mvc;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/user")
public class UserController {

    Logger logger = Logger.getLogger(UserController.class);

    @RequestMapping("register")
    public String register() {
        logger.info("invoke register");
        return "user/register";
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView createUser(User user) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("user/createSuccess");
        mav.addObject("user", user);
        return mav;
    }
}

三、請求接收

DispatcherServlet的類繼承關係如下:

可以看出,DispatcherServlet是一個HttpServlet,因此,它可以處理http請求。

在瀏覽器中輸入http://localhost:8080/spring-mvc-demo/user/register,因為在web伺服器上配置了spring-mvc-demo的contextPath為spring-mvc-demo,所以/spring-mvc-demo/user/register的請求就會被DispatcherServlet處理,請求處理路徑如下:

請求由tomcat傳遞給了DispatcherServlet了,DispatcherServlet接收後,就開始自己的特殊處理了。