Spring 原始碼閱讀之標籤解析

bokerr發表於2023-04-06

全域性目錄.md

引子

1、容器最基本使用.md

系列1 - bean 標籤解析:

2、XmlBeanFactory 的類圖介紹.md

3、XmlBeanFactory 對xml檔案讀取.md

4、xml配置檔案解析之【預設】名稱空間【標籤】的解析.md

5、xml配置檔案解析之【自定義】名稱空間【標籤】的解析.md

系列2 - bean 獲取: getBean() 做了什麼

前言

說到 spring 是個學 java的人都能說上兩嗓子,人均三板斧不過分吧。

兩年前我走馬觀花一樣的過了一遍 spring 原始碼,自以為已經漸漸上道了。實際上過了兩年到了今天,忘了太多太多東西了,所以只好再拿起來看看。

先進入第一個專題, spring-bean.xml 的解析

到了如今,各種好用、便捷的註解已經漫天飛了,相信幾乎不會再有新專案透過這種方式開發了,但是我覺得如果真的需要深入理解spring的原始碼,我們再去仔細揣摩這個載入過程,想必也會有所得。

正所謂,萬變不離其宗,雖然透過一系列註解簡化了太多太多的配置,但是我覺得我們從最初的樣子,往往更能從本質上去理解他。

1、極簡的測試案例

xml 配置

可能格式不一定對,我從原始碼包裡拷了一個過來改了一下當作案例

測試虛擬碼

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class XmlBeanFactoryTest {
	BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("bean.xml"));
	Object object = beanFactory.getBean("action");
}

上述就是 spring 最原始的使用方式了,我想只要路徑、名稱空間配置對了,執行起來問題不大。

別看方法體內只有兩行程式碼:

  • 1.將xml 檔案載入到 BeanFactory
  • 2.從BeanFactory 獲取Bean

為了講清楚這兩行程式碼背後發生了什麼,我們後邊將會分成多個章節,進行敘述。

【相信我絕對是萬惡之源了】

2、一些猜想

正式進入文章分析之前,我們不妨大膽的猜想一下,假如由我們自己來實現,spring 的容器功能,那我們要怎麼做呢?

我們先問一個問題:java是物件導向的語言,那麼物件怎麼來的?當然不是相親相出來的物件。

以前寫過一篇部落格,物件的來源就如圖中這麼幾種:

地址:

https://www.cnblogs.com/bokers/p/15904369.html

克隆和序列化都不是無中生有的方案,所以我們暫且忽略

那麼剩下如下的方式可以無中生有:

  • new 建立
  • 反射 建立

前文的例子中,我們也沒有顯式的建立我們在bean.xml 中定義的物件,所以是反射。

再看 bean.xml 中定義的 bean的class 屬性,這不妥妥的類路徑麼?

總結一下,那麼我們可以猜測 spring 原始碼中可能會包含如下的元件:

  • bean.xml 配置檔案讀取 ----- 元件
  • 配置檔案:格式校驗、內容解析,以及解析結果的快取 ----- 元件
  • 根據解析結果讀取類資訊 ----- 元件
  • 應用反射工具獲取類的例項物件 ----- 元件

2.1 擴充:

  • 更進一步,如果要保證單例,那麼勢必會有一個bean的全域性快取等等,"工廠" 這不他就悄悄的來了。

    spring 原始碼中大量的用到了 "工廠模式"

  • 如果懂代理的童鞋,應該知道一個叫做動態代理的東西,CGLIB 你可識得?面向切面程式設計,這不他就來了?

    在解析bean的時候,我們完全可以透過動態代理(為原類生成子類),附加一些行為上去,比如方法的攔截實現:

    • 生成動態代理後,在方法呼叫前後植入我們想要的操作,這就是AOP了

2.2 套娃擴充:

想必你也會注意到這麼一個問題:

比如很多工具明明不見得是spring 官方推出的,為什麼他們就是能跟spring 進行很好的整合呢? 比如日常使用的各種資料來源、ORM框架、日誌框架、訊息佇列,他們往往能透過幾個註解輕鬆注入spring 容器中。

這是因為spring 官方不僅僅授人以魚,還授人以漁。

沒錯spring 還提供了第三方外掛接入的手段,只需要按照spring給出的規範去開發我們自己的 xml標籤、自定義註解及其配套的解析工具。
自然就能實現把自己的工具整合到spring框架上。

不過不用擔心,實際上接入spring配適的活,基本都由各個外掛官方自己幹了。 不然你以為憑什麼,你寫個 xml配置,你就敢跟人吹水:我把某某外掛整合到spring框架上了。

實際上別人已經把粘合劑生產出來了,我們只是拉了個皮條。

廢話講完,接下來就應該去看看那兩行程式碼到底幹了啥了:

2.3 醜話說在前頭

XmlBeanFactory 實際上已經被廢棄了,這裡依然還要講它的目的主要是為了學習;雖然這個類被廢棄了,但是它的父類:DefaultListableBeanFactory 至今任然是 spring 中絕對的主角之一。

這裡名為學習 XmlBeanFactory,實際上是學習它的父類:DefaultListableBeanFactory。

都是從 xml 配置檔案切入,實際上現今官方推薦使用的是:ClassPathXmlApplicationContext 而非 XmlBeanFactory。

而這裡還把 XmlBeanFactory 拿出來講,還有一個目的:

  • 我們可以窺見,spring的發展歷程:從 XmlBeanFactory 到當下的 ClassPathXmlApplicationContext
  • XmlBeanFactory 足夠簡單。
    • ClassPathXmlApplicationContext 足夠強大,但是它也要比 XmlBeanFactory 複雜得多;

      實際上 我們對 XmlBeanFactory 的學習成果,可以作為 ClassPathXmlApplicationContext 的子集

      所以 就算 XmlBeanFactory 已經廢棄了,我們還是可以繼續學習它的。

繫好安全帶,發車了。

3. 這是第一行

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("bean.xml"));

這裡會有4篇部落格:

3.1 介紹 XmlBeanFactory 的類圖:

3.2 介紹 XmlBeanFactory 解析xml配置檔案的過程

3.3 spring 預設名稱空間標籤解析

例如: beans、import、bean、alias

3.4 使用者自定義名稱空間標籤解析

可以認為是我們自己對 spring 預設標籤的魔改。

4. 這是第二行

  • todo

還不知道需要多少篇幅介紹它

Object object = beanFactory.getBean("action");

相關文章