溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring MVC啟動過程的示例分析

發布時間:2021-08-26 13:16:11 來源:億速云 閱讀:146 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“Spring MVC啟動過程的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Spring MVC啟動過程的示例分析”這篇文章吧。

一、前置知識

大家都知道,我們在使用spring mvc時通常會在 web.xml 文件中做如下配置:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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_3_0.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>dispatcher</servlet-name>
 	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 	<init-param>
 		<param-name>contextConfigLocation</param-name>
 		<param-value>classpath:applicationContext-mvc.xml</param-value>
 	</init-param>
 	<load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
 	<servlet-name>dispatcher</servlet-name>
 	<url-pattern>/</url-pattern>
 </servlet-mapping>

</web-app>

上面的配置總結起來有幾點內容,分別是:DispatcherServlet

當我們將spring mvc應用部署到tomcat時,當你不配置任何的 context-paramlistener 參數,只配置一個 DispatcherServlet 時,那么tomcat在啟動的時候是不會初始化spring web上下文的,換句話說,tomcat是不會初始化spring框架的,因為你并沒有告訴它們spring的配置文件放在什么地方,以及怎么去加載。所以 listener 監聽器幫了我們這個忙,那么為什么配置監聽器之后就可以告訴tomcat怎么去加載呢?因為 listener 是實現了servlet技術規范的監聽器組件,tomcat在啟動時會先加載 web.xml 中是否有servlet監聽器存在,有則啟動它們。 ContextLoaderListener 是spring框架對servlet監聽器的一個封裝,本質上還是一個servlet監聽器,所以會被執行,但由于 ContextLoaderListener 源碼中是基于 contextConfigLocationcontextClass 兩個配置參數去加載相應配置的,因此就有了我們配置的 context-param 參數了, servlet 標簽里的初始化參數也是同樣的道理,即告訴web服務器在啟動的同時把spring web上下文( WebApplicationContext )也給初始化了。

上面講了下tomcat加載spring mvc應用的大致流程,接下來將從源碼入手分析啟動原理。

二、Spring MVC web 上下文啟動源碼分析

假設現在我們把上面 web.xml 文件中的 <load-on-startup>1</load-on-startup> 給去掉,那么默認tomcat啟動時只會初始化spring web上下文,也就是說只會加載到 applicationContext.xml 這個文件,對于 applicationContext-mvc.xml 這個配置文件是加載不到的, <load-on-startup>1</load-on-startup> 的意思就是讓 DispatcherServlet 延遲到使用的時候( 也就是處理請求的時候 )再做初始化。

我們已經知道spring web是基于 servlet 標準去封裝的,那么很明顯,servlet怎么初始化, WebApplicationContext web上下文就應該怎么初始化。我們先看看 ContextLoaderListener 的源碼是怎樣的。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
 // 初始化方法
 @Override
 public void contextInitialized(ServletContextEvent event) {
 	initWebApplicationContext(event.getServletContext());
 }
 // 銷毀方法
 @Override
 public void contextDestroyed(ServletContextEvent event) {
 	closeWebApplicationContext(event.getServletContext());
 	ContextCleanupListener.cleanupAttributes(event.getServletContext());
 }
}

ContextLoaderListener 類實現了 ServletContextListener ,本質上是一個servlet監聽器,tomcat將會優先加載servlet監聽器組件,并調用 contextInitialized 方法,在 contextInitialized 方法中調用 initWebApplicationContext 方法初始化Spring web上下文,看到這煥然大悟,原來Spring mvc的入口就在這里,哈哈~~~趕緊跟進去 initWebApplicationContext 方法看看吧!

initWebApplicationContext() 方法:

// 創建web上下文,默認是XmlWebApplicationContext
if (this.context == null) {
 this.context = createWebApplicationContext(servletContext);
}

if (this.context instanceof ConfigurableWebApplicationContext) {
 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
 // 如果該容器還沒有刷新過
 if (!cwac.isActive()) {
 	if (cwac.getParent() == null) {
 		ApplicationContext parent = loadParentContext(servletContext);
 		cwac.setParent(parent);
 	}
 	// 配置并刷新容器
 	configureAndRefreshWebApplicationContext(cwac, servletContext);
 }
}

上面的方法只做了兩件事:

1、如果spring web容器還沒有創建,那么就創建一個全新的spring web容器,并且該容器為root根容器,下面第三節講到的servlet spring web容器是在此根容器上創建起來的

2、配置并刷新容器

上面代碼注釋說到默認創建的上下文容器是 XmlWebApplicationContext ,為什么不是其他web上下文呢?為啥不是下面上下文的任何一種呢?

Spring MVC啟動過程的示例分析

我們可以跟進去 createWebApplicationContext 后就可以發現默認是從一個叫 ContextLoader.properties 文件加載配置的,該文件的內容為:

復制代碼 代碼如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

具體實現為:

protected Class<?> determineContextClass(ServletContext servletContext) {
 // 自定義上下文,否則就默認創建XmlWebApplicationContext
 String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
 if (contextClassName != null) {
  try {
  	return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
  }
  catch (ClassNotFoundException ex) {
  	throw new ApplicationContextException(
  			"Failed to load custom context class [" + contextClassName + "]", ex);
  }
 }
 else {
  // 從屬性文件中加載類名,也就是org.springframework.web.context.support.XmlWebApplicationContext
  contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
  try {
  	return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
  }
  catch (ClassNotFoundException ex) {
  	throw new ApplicationContextException(
  			"Failed to load default context class [" + contextClassName + "]", ex);
  }
 }
}

上面可以看出其實我們也可以自定義spring web的上下文的,那么怎么去指定我們自定義的上下文呢?答案是通過在 web.xml 中指定 contextClass 參數,因此第一小結結尾時說 contextClass 參數和 contextConfigLocation 很重要~~至于 contextConfigLocation 參數,我們跟進 configureAndRefreshWebApplicationContext 即可看到,如下圖:

Spring MVC啟動過程的示例分析

總結:

spring mvc啟動流程大致就是從一個叫 ContextLoaderListener 開始的,它是一個servlet監聽器,能夠被web容器發現并加載,初始化監聽器 ContextLoaderListener 之后,接著就是根據配置如 contextConfigLocationcontextClass 創建web容器了,如果你不指定 contextClass 參數值,則默認創建的spring web容器類型為 XmlWebApplicationContext ,最后一步就是根據你配置的 contextConfigLocation 文件路徑去配置并刷新容器了。

三、 DispatcherServlet 控制器的初始化

好了,上面我們簡單地分析了Spring mvc容器初始化的源碼,我們永遠不會忘記,我們默認創建的容器類型為 XmlWebApplicationContext ,當然我們也不會忘記,在 web.xml 中,我們還有一個重要的配置,那就是 DispatcherServlet 。下面我們就來分析下 DispatcherServlet 的初始化過程。

DispatcherServlet ,就是一個servlet,一個用來處理request請求的servlet,它是spring mvc的核心,所有的請求都經過它,并由它指定后續操作該怎么執行,咋一看像一扇門,因此我管它叫“閘門”。在我們繼續之前,我們應該共同遵守一個常識,那就是-------無論是監聽器還是servlet,都是servlet規范組件,web服務器都可以發現并加載它們。

下面我們先看看 DispatcherServlet 的繼承關系:

Spring MVC啟動過程的示例分析

看到這我們是不是一目了然了, DispatcherServlet 繼承了 HttpServlet 這個類, HttpServlet 是servlet技術規范中專門用于處理http請求的servlet,這就不難解釋為什么spring mvc會將 DispatcherServlet 作為統一請求入口了。

因為一個servlet的生命周期是 init() -> service() -> destory() ,那么 DispatcherServlet 怎么初始化呢?看上面的繼承圖,我們進到 HttpServletBean 去看看。

果不其然, HttpServletBean 類中有一個 init() 方法, HttpServletBean 是一個抽象類, init() 方法如下:

Spring MVC啟動過程的示例分析

可以看出方法采用 final 修飾,因為 final 修飾的方法是不能被子類繼承的,也就是子類沒有同樣的 init() 方法了,這個 init 方法就是 DispatcherServlet 的初始化入口了。

接著我們跟進 FrameworkServletinitServletBean() 方法:

Spring MVC啟動過程的示例分析

在方法中將會初始化不同于第一小節的web容器,請記住,這個新的spring web 容器是專門為 dispactherServlet 服務的,而且這個新容器是在第一小節根ROOT容器的基礎上創建的,我們在 <servlet> 標簽中配置的初始化參數被加入到新容器中去。

至此, DispatcherSevlet 的初始化完成了,聽著有點蒙蔽,但其實也是這樣,上面的分析僅僅只圍繞一個方法,它叫 init() ,所有的servlet初始化都將調用該方法。

總結:

dispactherServlet 的初始化做了兩件事情,第一件事情就是根據根web容器,也就是我們第一小節創建的 XmlWebApplicationContext ,然后創建一個專門為 dispactherServlet 服務的web容器,第二件事情就是將你在web.xml文件中對 dispactherServlet 進行的相關配置加載到新容器當中。

三、每個request調用請求經歷了哪些過程

其實說到這才是 dispatcherServlet 控制器的核心所在,因為web框架無非就是接受請求,處理請求,然后響應請求。當然了,如果 dispactherServlet 只是單純地接受處理然后響應請求,那未免太弱了,因此spring設計者加入了許許多多的新特性,比如說攔截器、消息轉換器、請求處理映射器以及各種各樣的 Resolver ,因此spring mvc非常強大。

dispatcherServlet 類不做相關源碼分析,因為它就是一個固定的執行步驟,什么意思呢?一個request進來,大致就經歷這樣的過程:

接受請求 -----> 是否有各種各樣的處理器 Handler -------> 是否有消息轉換器 HandlerAdapter --------> 響應請求

上面每一步如果存在相應的組件,當然前提是你在項目中有做相關的配置,則會執行你配置的組件,最后響應請求。因此明白大致的流程之后,如果你想調試一個request,那么你完全可以在 dispatcherServlet 類的 doDispatch 方法中打個斷點,跟完代碼之后你就會發現其實大致流程就差不多了。

四、后話

本文的工程是基于傳統的web.xml加載web項目,當然在spring mvc中我們也可以完全基于注解的方式進行配置,我們可以通過實現 WebApplicationInitializer 來創建自己的web啟動器,也可以通過繼承 AbstractAnnotationConfigDispatcherServletInitializer 來創建相應的spring web容器(包括上面說到的根容器和servlet web容器),最后通過繼承 WebMvcConfigurationSupport 再一步進行自定義配置(相關攔截器,bean等)

以上是“Spring MVC啟動過程的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女