這篇文章給大家介紹Spring MVC的上下文在Web容器中的啟動是怎樣的,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
Spring IoC是一個獨立的模塊,并不能直接在Web容器中發揮作用。
所以要在Web容器中使用IoC容器,需要為Spring IoC設計一個啟動過程,并把IoC容器導入進來
Web容器的啟動過程一方面處理Web容器的啟動,另一方面將IoC容器載入到web環境中并將其初始化
而Spring MVC是建立在IoC容器的基礎上的,在導入IoC容器后才能建立MVC
在常見的web.xml中需要配置一個DispatcherServlet類型的servlet和一個ContextLoaderListener類型的listener
Spring MVC通過這兩個類在Web容器中建立MVC,并將創建好的容器放到ServletContext中
ContextLoaderListener用于實現Spring IoC的啟動,創建IoC容器作為"根容器"
DispatcherServlet創建另一個IoC容器,并與根容器搭建雙親容器,完成MVC的建立
ContextLoaderListener調用方法contextInitialized()實現IoC容器的啟動
DispatcherServlet調用父類的init()方法創建IoC容器和搭建雙親容器,以搭建好的IoC容器為基礎建立MVC
此initWebApplicationContext()方法的實現在ContextLoaderListener的父類ContextLoader中
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 如果ServletContext已經存在根容器,說明已經創建過根容器,就不需要再執行下面的流程
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw ...
}
try {
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) {
// Spring5以后此方法直接返回null值
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 執行容器的refresh()方法刷新容器
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 將容器作為根容器。以指定常量為key,容器為value將其添加到ServletContext中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
return this.context;
}
catch (Error err) {
throw err;
}
}init() —— initServletBean() —— initWebApplicationContext()
此initWebApplicationContext()方法的實現在DispatcherServlet的父類FrameworkServlet中
protected WebApplicationContext initWebApplicationContext() {
// 從ServletContext中獲取根容器
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 默認this.webApplicationContext==null
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
// 將根容器作為父容器
cwac.setParent(rootContext);
}
// 啟動容器
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
// 如果wac還是為null就創建容器,并將根容器設置為父容器
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 搭建MVC,初始化Spring MVC的九大組件
onRefresh(wac);
}
// 獲取 由DispatcherServlet創建的容器名,以kv方式放進ServletContext中
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw ...
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
// 設置雙親容器
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
/** 配置并刷新容器
* 在刷新容器時,會為容器創建一個BeanFactory對象。
* 調用DefaultListableBeanFactory的構造方法時會嘗試獲取父容器并將父容器本身或父容器持有的BeanFactory作為此BeanFactory的parentBeanFactory
這個parentBeanFactory會在getBean中被用到(在獲取bean前,先嘗試從父工廠中獲取bean)
**/
configureAndRefreshWebApplicationContext(wac);
return wac;
}關于Spring MVC的上下文在Web容器中的啟動是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。