日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 源码阅读 之 Spring框架加载

發布時間:2025/3/15 javascript 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 源码阅读 之 Spring框架加载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  說起第一次閱讀Spring Framework源碼,大概還是2010年吧,那個時候還不懂技巧和方法,一頭扎在代碼的汪洋大海里,出不來了。后面幾年偶爾斷斷續續的也看過幾次,都是不得要領,最后都是無疾而終。所以覺得閱讀這種大型的代碼項目,很吃力,也很艱難,需要不斷的堅持。?

  最近項目不是很忙,下班早,就又把Spring的源碼翻出來看看,也看了一段時間了,這次算是小有收獲吧,于是打算學博客記錄下來。?

  在這之前,并沒有打算在繼續寫博客,因為這里的這種討厭的限制,而且也越來越不喜歡這里的風格。但是有覺得,學過的東西,既然有價值,就記錄下來吧,好記性不如爛筆頭,不記得的時候可以打開看看。在這之前,我的一些學習筆記一直是使用為知筆記來記錄的,現在把記錄在為知筆記里的內容重新翻出來整理一下,帖子博客上吧。

  好了,開始進入正題吧:

----------------------------------------------------------------------------------------------------

  在使用Spring Framework的時候,各種教程都是介紹首先要在 web.xml 里面配置一個?listener,該?listener 會在web容器啟動的時候依次加載,從而來加載Spring Framework。那就從這個?listener 開始閱讀吧。

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

  ContextLoaderListener 實現了?ServletContextListener 接口,因此 ContextLoaderListener?監聽了當前Web Application的生命周期,在 Web?容器啟動時會調用其實現的?contextInitialized() 方法來加載Spring Framework框架,當容器終止時會調用 其?contextDestroyed() 方法來銷毀資源。?ContextLoaderListener類的contextInitialized()方法是這樣實現的:

public void contextInitialized(ServletContextEvent event) {this.contextLoader = createContextLoader();if (this.contextLoader == null) {this.contextLoader = this;}this.contextLoader.initWebApplicationContext(event.getServletContext()); }

  這個方法很簡單,但是我實在不明白框架的設計者為什么要先判斷 contextLoader 是否為 null,然后再通過 contextLoader 來調用?initWebApplicationContext() 方法,而為什么不在 contextInitialized()方法里直接調用?initWebApplicationContext() 方法,一行代碼就搞定的事,為什么還這么麻煩??

  為什么會有這樣的疑問呢,因為initWebApplicationContext()方法是ContextLoader類的成員方法,而ContextLoaderListener 又繼承自?ContextLoader,initWebApplicationContext()方法是用public進行修飾的,因此該方法也得到?ContextLoaderListener 繼承,也就是說ContextLoaderListener也擁有此方法。那么作者為什么還要在該類里增加一個ContextLoader類型的成員變量contextLoader,用 contextLoader?來調用?initWebApplicationContext()呢? 看了一下整個ContextLoaderListener類,contextLoader 都是調用其自身的方法,而這些方法也被ContextLoaderListener繼承了,實在是想不通。

  進入?initWebApplicationContext() 方法,該方法實現了整個Spring的加載。該方法除去log和try/catch代碼,真正的代碼也不是很多。外表看似簡單,但是里面的邏輯實現,完全超乎我的想象,直接看代碼吧: 

1 public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 2 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { 3 throw new IllegalStateException( 4 "Cannot initialize context because there is already a root application context present - " + 5 "check whether you have multiple ContextLoader* definitions in your web.xml!"); 6 } 7 8 Log logger = LogFactory.getLog(ContextLoader.class); 9 servletContext.log("Initializing Spring root WebApplicationContext"); 10 if (logger.isInfoEnabled()) { 11 logger.info("Root WebApplicationContext: initialization started"); 12 } 13 long startTime = System.currentTimeMillis(); 14 15 try { 16 // Store context in local instance variable, to guarantee that 17 // it is available on ServletContext shutdown. 18 if (this.context == null) { 19 this.context = createWebApplicationContext(servletContext); 20 } 21 if (this.context instanceof ConfigurableWebApplicationContext) { 22 configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext); 23 } 24 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); 25 26 ClassLoader ccl = Thread.currentThread().getContextClassLoader(); 27 if (ccl == ContextLoader.class.getClassLoader()) { 28 currentContext = this.context; 29 } 30 else if (ccl != null) { 31 currentContextPerThread.put(ccl, this.context); 32 } 33 34 if (logger.isDebugEnabled()) { 35 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + 36 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); 37 } 38 if (logger.isInfoEnabled()) { 39 long elapsedTime = System.currentTimeMillis() - startTime; 40 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); 41 } 42 43 return this.context; 44 } 45 catch (RuntimeException ex) { 46 logger.error("Context initialization failed", ex); 47 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); 48 throw ex; 49 } 50 catch (Error err) { 51 logger.error("Context initialization failed", err); 52 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); 53 throw err; 54 } 55 }

? ? 代碼第二行,從 servletContext取出以?org.springframework.web.context.WebApplicationContext.ROOT 為key的對象,如果該對象不等于null,說明當前servletContext已經加載成功了Spring,則直接拋出異常。為什么要做此判斷呢?難道是當前Web容器啟動了多個Web應用,每個應用都使用了Spring框架框架嗎?如果是這樣,則每個Web應用都對應著一個單獨的ServletContext,是不會出現這種問題的,貌似也就只又在 web.xml里面配置多個 類似的加載 Spring Framework的listener才會觸發此問題。好了,那?org.springframework.web.context.WebApplicationContext.ROOT 又是在何時放進 servletContext 的呢? 在第24行的地方,當代碼執行到第24行的地方時,說明整個Spring框架已經加載并初始化完畢。 ??

????代碼第29行,調用 createWebApplicationContext() 方法創建Spring Web應用上下文。Spring Web應用上下文是怎么創建的呢?下文在繼續。。。

轉載于:https://www.cnblogs.com/yangliu9420/p/3516658.html

總結

以上是生活随笔為你收集整理的Spring 源码阅读 之 Spring框架加载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。