1 DispatcherServlet
和其他web框架一樣,Spring MVC也是圍繞前端控制器模式設計,其中有一箇中心Servlet,叫做DispatcherServlet,爲請求處理提供一個 共享算法,實際的工作交給可配置的委託組件執行。這樣的模式非常靈活,可以支持不同的工作流。
與任何Servlet一樣,DispatcherServlet需要根據Servlet規範使用Java配置或在web.xml聲明和映射。反過來,DispatcherServlet使用Spring配置爲請求映射、視圖解析、異常控制等找到需要的委託組件。
下面的Java配置示例註冊並初始化DispatcherServlet, Servlet容器將自動檢測DispatcherServlet。
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
除了使用Servlet API,還可以繼承AbstractAnnotationConfigDispatcherServletInitializer並覆蓋特定的方法
下面使用web.xml配置的方式註冊和初始化DispatcherServlet.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Spring引導遵循不同的初始化順序。Spring Boot沒有掛接到Servlet容器的生命週期中,而是使用Spring配置來引導自身和嵌入的Servlet容器.過濾器和Servlet聲明在Spring配置中檢測到,並向Servlet容器註冊。
1.1 上下文層級
DispatcherServlet需要WebApplicationContext(普通ApplicationContext的擴展)用於自己的配置。WebApplicationContext有一個指向ServletContext及其關聯的Servlet的鏈接。它還綁定到ServletContext,以便應用程序可以使用requestcontext上的靜態方法來查找WebApplicationContext(如果它們需要訪問它)
於許多應用程序來說,擁有一個單一的WebApplicationContext就足夠了。也可以有一個上下文層次結構,其中一個根WebApplicationContext在多個DispatcherServlet(或其他Servlet)實例之間共享,每個實例都有自己的子WebApplicationContext配置。
根WebApplicationContext通常包含基礎設施bean,比如需要在多個Servlet實例之間共享的數據存儲庫和業務服務。這些bean可以有效地繼承,並且可以在特定於Servlet的子WebApplicationContext中重寫(即重新聲明),該上下文通常包含給定Servlet的本地bean。下圖顯示了這種關係:
下面的示例配置WebApplicationContext層次結構
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
}
如果不需要應用程序上下文層次結構,則應用程序可以通過getRootConfigClasses()返回所有配置,並從getServletConfigClasses()返回null
下面展示作用效果相同的web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app1-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app1</servlet-name>
<url-pattern>/app1/*</url-pattern>
</servlet-mapping>
1.2 特殊bean類型
DispatcherServlet委託特殊bean來處理請求並呈現適當的響應,這裏所說的“特殊bean”是指實現框架約定的spring管理的對象實例。這些通常帶有內置的約定,但是您可以自定義它們的屬性並擴展或替換它們。
下表列出了DispatcherServlet檢測到的特殊bean:
Bean 類型 | 解釋 |
---|---|
HandlerMapping | 將請求和帶有攔截器列表的處理器映射,用於預處理和後處理。映射基於一些標準,其細節因HandlerMapping實現而異。兩個主要的HandlerMapping實現是RequestMappingHandlerMapping(它支持@RequestMapping註解的方法)和SimpleUrlHandlerMapping(它維護URI路徑模式到處理程序的顯式註冊)。 |
HandlerAdapter | 幫助DispatcherServlet調用映射到請求的處理程序,而不管實際如何調用處理程序。例如,調用帶註釋的控制器需要解析註釋。HandlerAdapter的主要目的是保護DispatcherServlet不受這些細節的影響。 |
HandlerExceptionResolver | 解決異常的策略,可能將異常映射到處理程序、HTML錯誤視圖或其他目標。 |
ViewResolver | 將從處理程序返回的基於邏輯字符串的視圖名稱解析爲要呈現給響應的實際視圖 |
LocaleResolver, LocaleContextResolver | 解析客戶端正在使用的語言環境和時區,以便能夠提供國際化的視圖 |
ThemeResolver | 解析web應用程序可以使用的主題——例如,提供個性化的佈局 |
MultipartResolver | 在一些多部分解析庫的幫助下解析多部分請求(例如,瀏覽器表單文件上傳)的抽象。 |
FlashMapManager | 存儲和檢索輸入和輸出FlashMap,可用於將屬性從一個請求傳遞到另一個請求,通常是通過重定向。 |