1. 程式人生 > >三、SpringMVC原理

三、SpringMVC原理

學習內容

1、Web環境下spring配置

2、根IoC容器的啟動

3、DispatcherServlet的啟動和初始化

4、MVC元件

5、MVC處理請求流程


 

一、web環境下spring配置

在web.xml中配置DispatcherServlet和ContextLoaderListener

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<context-param>

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

<param-value>classpath:applicationContext.xml</param-value>

</context-param>

 

<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:spring/springmvc-servlet.xml</param-value>

</init-param>

</servlet>

<servlet-mapping>

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

<url-pattern>/</url-pattern>

</servlet-mapping>


 

二、根IoC容器的啟動

以ContextLoaderListener為起點,繼承關係如下圖:

 

 

生命週期與ServletContext對應。

public interface ServletContextListener extends EventListener {

 

//當ServletContext初始化時,回撥這個方法,初始化Ioc容器

public void contextInitialized(ServletContextEvent sce);

 

//當ServletContext銷燬時,回撥這個方法,銷燬Ioc容器

public void contextDestroyed(ServletContextEvent sce);

}

 

Ioc載入過程由ContextLoader中完成,過程大致為,從ServletContext中獲取在web.xml中配置的引數,如spring配置檔案路徑以及其他容器啟動引數等。然後進行配置檔案載入等一系列Spring IoC容器初始化過程。此IoC容器型別為WebApplicationContext。

以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE為key,IoC容器例項為value,放入ServletContext,以便全域性獲取。

public interface WebApplicationContext extends ApplicationContext {

 

//該常量為ServletContext中key,value為WebApplicationContext例項,則

該容器可在web應用全域性獲取

String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";


 

三、DispatcherServlet的啟動和初始化

DispatcherServlet的繼承關係如下

 

a、MVC Ioc容器的啟動

由繼承關係可知,在Servlet建立時,會進行Spring MVC IoC容器的初始化工作。DispatcherServlet也會建立一個IoC容器(用於存放MVC Bean)與之對應,並且設定雙親容器為根容器,由IoC工作原理可知,向IoC容器getBean時,會先向雙親容器中獲取,無法得到才從自身獲取。所以根容器可以被其他Servlet容器共享。

 

b、初始化

在Spring MVC IoC容器初始化完成後。接著對MVC元件初始化,在initStrategies()方法完成。

protected void initStrategies(ApplicationContext context) {

initMultipartResolver(context);

initLocaleResolver(context);

initThemeResolver(context);

initHandlerMappings(context);

initHandlerAdapters(context);

initHandlerExceptionResolvers(context);

initRequestToViewNameTranslator(context);

initViewResolvers(context);

initFlashMapManager(context);

}

 

initHandlerMappings()

initHandlerMappings() 方法從 SpringMVC 容器及 Spring 的容器中查詢所有的 HandlerMapping 例項,並把它們放入到 handlerMappings 這個 list 中。這個方法並不是對 HandlerMapping 例項的建立,HandlerMapping 例項是在Spring MVC容器初始化完成建立的。

initHandlerAdapters ()、initViewResolvers()的工作都與initHandlerMappings()類似。


 

四、MVC元件

 

1、HandlerMapping

HandlerMapping的作用是根據當前請求的找到對應的 Handler,並將 Handler(處理器)與請求對應的所有 HandlerInterceptor(攔截器)封裝到 HandlerExecutionChain 物件中。

HandlerMapping 介面的內部只有一個方法:

HandlerExecutionChain getHandler(HttpServletRequest request)。

HandlerMapping 是由 DispatcherServlet 呼叫,DispatcherServlet 會從容器中取出所有 HandlerMapping 例項並遍歷,讓 HandlerMapping 例項根據自己實現類的方式去嘗試查詢 Handler。

 

Handler 可以是 HandlerMethod(封裝了 Controller 中的方法)物件,也可以是 Controller 物件、 HttpRequestHandler 物件或 Servlet 物件,而 Handler 具體是哪種物件,與所使用的 HandlerMapping 實現類有關。

HandlerMapping 實現類有兩重型別,分別繼承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 HttpRequestHandler、Controller 或 Servlet),它們又統一繼承於 AbstractHandlerMapping。橫線中為三個常見HandlerMapping 實現類。

 

a、AbstractUrlHandlerMapping

獲取的 Handler 的型別實際是一個 Controller 類,所以一個 Controller 只能對應一個請求。

實現類有:

1) ControllerClassNameHandlerMapping:根據類名訪問 Controller。

2) BeanNameUrlHandlerMapping:利用 BeanName 來作為 URL 使用。

3) ControllerBeanNameHandlerMapping:根據 Bean 名訪問 Controller,與 BeanNameUrlHandlerMapping 類似,但是bean名稱不用遵循URL公約。

4) SimpleUrlHandlerMapping:可以將 URL 與處理器的定義分離,還可以對 URL 進行統一的對映管理。

 

b、AbstractHandlerMethodMapping

獲取的 Handler 的型別是 HandlerMethod,Handler 是一個方法,它儲存了方法的資訊(如Method),所以一個 Controller 就可以處理多個請求。

AbstractHandlerMapping 只有一個實現類 RequestMappingHandlerMapping。

 

 

2、HandlerAdapter

根據 Handler 來找到支援它的 HandlerAdapter,通過 HandlerAdapter 執行這個 Handler 得到 ModelAndView 物件。

HandlerAdapter 介面中的方法:

public interface HandlerAdapter {

 

//判斷當前HandlerAdapter是否支援這個Handler

boolean supports(Object handler);

 

//呼叫Handler處理請求

ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

 

//

long getLastModified(HttpServletRequest request, Object handler);

 

}

繼承關係

 

a、RequestMappingHandlerAdapter

RequestMappingHandlerMapping 獲取的 Handler 是 HadnlerMethod 型別,它代表 Controller 裡要執行的方法,RequestMappingHandlerAdapter 可以執行 HadnlerMethod 物件。

RequestMappingHandlerAdapter 的 handle() 方法是在它的父類 AbstractHandlerMethodAdapter 類中實現

@Override

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

return handleInternal(request, response, (HandlerMethod) handler);

}

handleInternal() 方法是由 RequestMappingHandlerAdapter 實現,以此類推

b、HttpRequestHandlerAdapter:執行 HttpRequestHandler 型別的 Handler

c、SimpleControllerHandlerAdapter:執行 Controller 型別的 Handler

d、SimpleServletHandlerAdapter:執行 Servlet 型別的 Handler

 

3、ViewResolver

根據檢視的名稱將其解析為 View 型別的檢視。通過 ModelAndView 中的檢視名稱將其解析成 View,View 是用來渲染頁面的,也就是將 Model 填入模板中,生成 html 或其他格式的檔案。

解析策略有JSP 、Velocity、FreeMaker、PDF檢視解析,如果設定了多個解析策略則可以通過 order 屬性來設定其優先順序,數值越小優先順序越高,前面的檢視解析器解析後就不會讓後面的繼續解析。預設的解析策略是 InternalResourceViewResolver,按照 JSP 頁面來解析。

繼承關係

標題


 

五、MVC處理請求流程

 

由DispatcherServlet為起點,進入原始碼可知,DispatcherServlet負責協調和組織各個元件完成初始化,及請求處理響應工作。

A、初始化:

在web容器啟動時,對 DispatcherServlet 進行例項化,然後呼叫它的 init() 方法進行初始化,在這個初始化過程中先建立SpringMVC的IOC容器,然後對元件進行初始化。

 

B、請求處理響應:

客戶端發出請求,web容器接收到這個請求後,如果匹配 DispatcherServlet 在 web.xml 中配置的對映路徑,就將請求轉交給 DispatcherServlet 處理;

DispatcherServlet 取出所有 HandlerMapping 例項(每個例項對應一個 HandlerMapping 介面的實現類)並遍歷,每個 HandlerMapping 會根據請求資訊,通過自己實現類中的方式去找到處理該請求的 Handler,並且將這個 Handler 與對應的 HandlerInterceptor 封裝成一個 HandlerExecutionChain 物件,一旦有一個 HandlerMapping 可以找到 Handler 則退出迴圈。

DispatcherServlet 取出所有 HandlerAdapter 元件,根據已經找到的 Handler,再從所有 HandlerAdapter 中找到可以處理該 Handler 的 HandlerAdapter 物件。執行 HandlerExecutionChain 中所有攔截器的 preHandler() 方法,然後再利用 HandlerAdapter 執行 Handler ,執行完成得到 ModelAndView,再依次呼叫攔截器的 postHandler() 方法。

根據返回的ModelAndView,選擇一個適合的ViewResolver,且必須是已經註冊到Spring容器中的ViewResolver,返回給DispatcherServlet。ViewResolver 將 ModelAndView 解析成 View,然後 View 會呼叫 render() 方法再根據 ModelAndView 中的資料渲染出頁面;

最後再依次呼叫攔截器的 afterCompletion() 方法。將渲染出的頁面返回給客戶端,請求結束。