溫馨提示×

溫馨提示×

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

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

Spring容器BeanFactory怎么使用

發(fā)布時間:2022-01-04 17:25:33 來源:億速云 閱讀:207 作者:iii 欄目:服務器

本篇內容主要講解“Spring容器BeanFactory怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring容器BeanFactory怎么使用”吧!

Spring容器

什么是Spring容器

Spring容器是Spring的核心,它可以創(chuàng)建對象,把他們關聯(lián)在一起,配置各個對象,并管理每個對象的整個生命周期。Spring容器使用依賴注入(DI)來管理組成一個應用程序的組件。這些對象被稱為Spring Beans (一個對象就是一個Bean)。

Spring中有兩種容器:

① BeanFactory 一個最簡單的Spring容器,給依賴注入(DI)提供了基礎的支持。

② ApplicationContext  此容器添加以一些企業(yè)需要用到的東西,更加全面。它包含了BeanFactory容器中的東西。

BeanFactory容器

在Spring中,有大量BeanFactory接口的實現(xiàn)類(見下圖),但是,最常用的也就是XmlBeanFactory類(在Eclipse中,查看其源碼可以看見已經(jīng)是一個過時的類了,但我們也需要了解。),它可以從一個 XML 文件中讀取配置元數(shù)據(jù),由這些元數(shù)據(jù)來生成一個被配置化的系統(tǒng)或者應用。

  Spring容器BeanFactory怎么使用

(BeanFactory接口實現(xiàn)類)

注:

本文主要是針對下面一行代碼執(zhí)行所發(fā)生的事情的一些深入探究。

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("配置文件"));

核心類介紹

Ⅰ. DefaultListableBeanFactory

XmlBeanFactory類繼承自DefaultListableBeanFacotry類,而DefaultListableBeanFactory類是Bean加載的核心部分,是Spring注冊及加載Bean的默認實現(xiàn)。

XmlBeanFactory類與DefaultListableBeanFactory類之間不同的地方就在于XmlBeanFactory類中使用了自定義的XML讀取器XmlBeanDefinitionReader,

      Spring容器BeanFactory怎么使用

(XmlBeanDefinitionReader對象)

實現(xiàn)了個性化的BeanDefinitionReader讀取,DefaultListableBeaFactory類繼承了AbstractAutoWireCapableBeanFactory類,并實現(xiàn)了ConfigurableListableBeanFactory以及BeanDefinitionRegistry接口。

    Spring容器BeanFactory怎么使用  

(DefaultListableBeanFactory類)

DefaultListableBeanFactory類的基類,實現(xiàn)接口的一些相關類圖:

    Spring容器BeanFactory怎么使用

(容器加載部分相關類圖)

XmlBeanFactory類就繼承自DefaultListableBeanFactory類。XmlBeanFactory類對DefaultListableBeanFactory類進行了擴展,在XMLBeanFactory中主要使用reader屬性對資源文件進行讀取和注冊。

XmlBeanFactory類的構造方法如下圖:

    Spring容器BeanFactory怎么使用

(XmlBeanFactory構造方法)

Ⅱ. XmlBeanDefinitionReader

上面我們已經(jīng)知道了XmlBeanFactory類和DefaultListableBeanFactory類的區(qū)別了,XmlBeanFactory類中定義了一個XmlBeanDefinitionReader對象,用于對資源文件進行處理。

XML配置文件的讀取對于Spring而言非常重要,因為Spring絕大部分功能都是以配置文件作為切入點的,那么,我們就要從XmlBeanDefinitionReader類中梳理一下資源文件讀取、解析和注冊的大致流程。

      Spring容器BeanFactory怎么使用

(配置文件讀取相關類)

通過上面配置文件讀取相關類圖可以得到讀取大致流程如下:

① 通過繼承自 AbstratcBeanDefinitionReader 中的方法,來使用 ResourceLoader 將資源文件路徑轉換為對應的 Resource 文件。

② 通過 DocumentLoader 對 Resource 文件進行轉換,將 Resource 文件轉換為 Document 文件。

③ 通過 DefaultBeanDefinitionDocumentReader 類對Document進行解析,并使用 BeanDefinitionParserDelegate 對 Element 進行解析。

上述三步只是讀取配置文件的一個大致流程,接下來將進行更加詳細的解析。

XmlBeanFactory

上面我們已經(jīng)知道了 XmlBeanFacotry 和 DefaultListableBeanFactory 的區(qū)別了。XmlBeanFactory 結構如下圖:

                        Spring容器BeanFactory怎么使用

(XmlBeanFactory類結構)

在Spring中,我們創(chuàng)建了一個配置文件,并且在配置文件中配置了一個Bean后,那么,我們就要獲取這個Bean。在測試代碼中我們都寫過這樣一句代碼:

XmlBeanFactory xmlBeanFactory = new XmlBeanFacotry(new ClassPathResource("配置文件"));

也可以是:

BeanFactory beanFactory = new XmlBeanFacotry(new ClassPathResource("配置文件"));

總之,以上兩句行代碼就是讀取配置文件創(chuàng)建容器。

那么,new XmlBeanFacotry(new ClassPathResource("配置文件")) 這句代碼到底是怎么回事呢?先看看下面的 XmlBeanFactory 初始化時序圖吧!(畫得不好,將就看吧)

      Spring容器BeanFactory怎么使用

(XmlBeanFactory初始化時序圖)

時序圖解析:

◆ 首先,時序圖從一個測試類開始,這個測試類就是上面創(chuàng)建 XmlBeanFactory 那里。

 ◆ 創(chuàng)建 XmlBeanFactory 需要一個 Resource 對象,由于 Resource 是接口,所以我們使用其實現(xiàn)類 ClassPathResource 來構造 Resource 資源文件的實例對象。

◆ 有了 Resource 對象就可以進行 XmlBeanFactory 的初始化了,最后得到一個 BeanFactory。

那么,問題來了,什么又是 Resource呢?它是怎么對資源進行封裝處理的呢?

 ● Resource 是什么

在說 Resource 之前,我們要知道一個接口:InputStreamSource,該接口封裝任何能返回 InputStream 的類,比如File、Classpath下的資源、Byte、Array等。它只定義了一個方法:InputStream getInputStream() throws IOException; 該方法返回一個 InputStream 對象。

Resource 接口抽象了所有 Spring 內部所使用到的底層資源: File、URL、Classpath等。Resource 接口中的方法及大致作用如下圖:

       Spring容器BeanFactory怎么使用

(Resource接口)

對于不同來源的資源文件都有對象的 Resource 實現(xiàn):

文件(FileSystemResource)、Classpath資源(ClassPathResource)、URL資源(UrlResource)等。

      Spring容器BeanFactory怎么使用

(資源文件處理部分相關類)

資源文件的加載在日常開發(fā)中也經(jīng)常被使用,可以直接使用 Spring 提供的類,如在加載文件時使用如下代碼:

Resource resource = new ClassPathResource("資源文件");

InputStream inputStream = resource.getInputStream();

得到 inputStream 后,我們就可以按照以往的開發(fā)方式進行開發(fā)了,而且還可以使用 Resource 及其實現(xiàn)類的一些東西。

當通過 Resource 相關類完成了對配置文件的封裝后,配置文件的讀取就是 XmlBeanDefinitionReader 來完成了。

現(xiàn)在我們已經(jīng)知道了 Spring 中將配置文件封裝為 Resource 對象,下面繼續(xù)了解 XmlBeanFactory 的初始化過程。從上面 XmlBeanFactory類結構圖中可以看出 XMLBeanFactory 類共有兩個構造方法,如下圖:

    Spring容器BeanFactory怎么使用

(XmlBeanFactory類構造方法)

從上圖我們看出,第一個構造方法內部調用了該類內部的另一個構造方法。所以,我們也就了解第二個構造方法了。

首先,在第一行出現(xiàn)了 super(parentBeanFactory) 這樣一句代碼,調用了父類(DefaultListableBeanFactory)的一個構造方法。

      Spring容器BeanFactory怎么使用

(DefaultListableBeanFactory有參構造方法)

來到父類構造方法,我們發(fā)現(xiàn)又繼續(xù)調用了父類(AbstractAutowireCapableBeanFactory)的構造方法,見下圖:

      Spring容器BeanFactory怎么使用

(AbstractAutowireCapableBeanFactory類構造方法)

從圖中可以看出,有參構造方法(我們使用的就是有參構造)先調用了本類中的一個無參構造方法,無參構造方法首先執(zhí)行了父類(AbstractBeanFactory)的構造方法(一個空方法),這里了解一下 ignoreDependencyInterface 方法,該方法的主要功能就是 忽略自動連接給定的依賴接口(忽略給定接口的自動裝配功能)。那么,該方法有什么用?
如:當 A類 中有屬性 B,當 Spring 在獲取 A 的 Bean 的時候如果屬性 B 還沒有被初始化,Spring 就會自動初始化 B,(這也是Spring的一個重要特性)。但是,某些情況下,B 不會被初始化,比如 B 實現(xiàn)了 BeanNameAware 接口。Spring API介紹:應用程序上下文通常使用它來注冊以其他方式解析的依賴項,如通過BeanFactoryAware實現(xiàn)的BeanFactory或通過ApplicationContextAware實現(xiàn)的ApplicationContext。默認情況下,只忽略BeanFactoryAware接口。若要忽略其他類型,請為每個類型調用此方法。

最后調用 setParentBeanFactory 方法設置 BeanFactory對象。

      Spring容器BeanFactory怎么使用

(setParentBeanFactory方法)

在 setParentBeanFactory 方法中有一個 if 判斷,用于判斷是否已經(jīng)關聯(lián)了 BeanFactory,如果已經(jīng)關聯(lián)就拋出異常。

? 加載Bean

在上面講到 Resource 時,我們知道了 XmlBeanFactory 的構造方法,我們也知道了其中一個構造方法首先調用了父類的構造方法,那么,在super()語句下面就是 this.reader.loadBeanDefinitions(resource) 方法的調用。這個方法才是整個資源加載的切入點,下面是該方法調用的時序圖:

    Spring容器BeanFactory怎么使用

(loadBeanDefinitions方法執(zhí)行時序圖)

從上圖可以看到,這個方法的調用引起了很大一串的工作。然而這些工作也只是在做準備工作,下面說說這里究竟在準備什么工作:

(1)封裝資源文件。當調用 loadBeanDefinitions 方法時,就會跳轉到該方法中,該方法就調用了本類的一個重載方法,同時根據(jù) Resource 對象創(chuàng)建一個EncodedResource 對象作為參數(shù)傳遞,使用 EncodedResource 的作用就是把 Resource 使用 EncodedResource 類進行封裝。

            Spring容器BeanFactory怎么使用

(loadBeanDefinitions(Resource resource)方法)

(2)獲取輸入流構建 inputSource。從 Resource 中獲取對應的 InputStream 并創(chuàng)建 InputSource。

            Spring容器BeanFactory怎么使用
(loadBeanDefinitions(EncodedResource encodedResource)方法中 獲取 InputStream 并 創(chuàng)建 InputSource)

(3)通過剛剛創(chuàng)建的 InputSource 對象和 Resource繼續(xù)調用 doLoadBeanDefinitions()方法。

              Spring容器BeanFactory怎么使用

(doLoadBeanDefinitions(InputSource, Resource)方法調用)

上面,我們多次看到 EncodedResource ,那么,它到底是什么?

? EncodedResource

通過名字可以猜測該類和編碼相關。該類主要就是對資源文件的編碼進行處理的。其中一個很重要的方法 getReader() 方法 ,當設置了編碼屬性時,Spring 就會使用相應的編碼作為輸入流的編碼。

首先看看它的一個構造方法:(該類一共有四個構造方法,但其余三個構造方法均調用了下面這個構造方法)

      Spring容器BeanFactory怎么使用

(EncodedResource類的一個構造方法)

該構造方法主要就是對類中的屬性進行初始化。

再來看看 getReader() 方法:

        Spring容器BeanFactory怎么使用
(getReader() 方法)

getReader() 方法構造了一個含編碼的 InputStreamReader。將 Resource 封裝為 EncodedResource 對象后,就來到了 XmlBeanDefinitionReader 類中的 loadBeanDefinitions() 方法(另一個重載后的方法),也就是下圖中的方法。

      Spring容器BeanFactory怎么使用

(loadBeanDefinitions(EncodedResource ..)方法部分重要代碼)

上圖方法才算是真正的數(shù)據(jù)準備,也就是往上第7張 時序圖中所描述的部分。

再次回顧以上數(shù)據(jù)準備部分內容,首先將傳入的 Resource 對象封裝為 EncodedResource,為什么需要封裝?目的是考慮到 Resource 可能存在編碼要求的情況,其次,通過SAX讀取XML文件的方式來準備 InputSource對象,最后將準備的數(shù)據(jù)通過參數(shù)傳遞給核心處理方法 doLoadBeanDefinitions(InputSource inputSource, Resource resource)。下面就來看看 doLoadBeanDefinitions() 方法做了什么事情:

      Spring容器BeanFactory怎么使用

(doLoadBeanDefinitions() 方法部分代碼(除catch部分))

doLoadBeanDefinitions() 方法 try 后面有多個 catch ,除開這些 catch,那么,這段代碼做了以下三件事情:

(1)獲取對 XML 文件的驗證模式

(2)加載 XML 文件,得到對應的 Document 對象

(3)根據(jù)返回的 Document 對象注冊 Bean 信息

以上三個操作支撐著整個Spring容器的實現(xiàn)基礎,下面就將從這三個步驟講起。

 ? 獲取 XML的驗證模式

XML 驗證模式的作用:用于保證 XML 文件的正確性(貌似就是所說的約束),常用的驗證模式有兩種:DTD(Document Type Definition) 和 XSD(XML Schemas Definition)。詳細了解驗證模式請自行上網(wǎng)搜索。

在上一張(doLoadBeanDefinitions方法代碼)圖中,我們看見 try 塊中第一行代碼是: Document document = doLoadDocument(inputSource, resource); 調用了本類中的 doLoadDocument() 方法,但是,這句代碼主要是用來獲取 Document對象的,也就是上面第二件事情;但是,在其中會先完成對 XML 文件驗證模式的獲取。

      Spring容器BeanFactory怎么使用

(doLoadDocument() 方法)

我們可以從上圖看到,在 loadDocument() 方法執(zhí)行時,先執(zhí)行了 getValidationModeForResource(resource) 方法,該方法返回一個 int 類型的值。(在 Spring3.2 中,并不存在 doLoadDocument() 方法,是直接在 doLoadBeanDefintions() 方法中調用 getValidationModeForResource(resource) 方法 和 loadDocument() 方法),下面我們看看 getValidationModeForResource(resource) 方法做了什么事情:

      Spring容器BeanFactory怎么使用

(getValidationModeForResource(resource) 方法)

在上面方法中,使用了幾個常量,下圖是幾個常量所表示的值:

      Spring容器BeanFactory怎么使用

(org.springframework.util.xml.XmlValidationModeDetector類中的幾個常量)

注意:XmlBeanDefinitionsReader 類中也有上圖中除了 DOCTYPE 常量以外的幾個 int 類型的同名的常量,其值就是上面的值。也就是 Spring 把不同的驗證模式使用了不同數(shù)值表示了而已。

在往上第二張圖中得知 getValidationModeForResource(resource) 方法首先判斷是否手動指定(通過 setValidationMode() 方法設置驗證模式)了驗證模式,判斷方式就是 獲取 validationMode 屬性進行判斷。否則使用自動檢測的方式,自動檢測調用了 org.springframework.beans.factory.xml.XmlBeanDefinitionReader.detectValidationMode(resource) 方法(本類中的方法)實現(xiàn)。

      Spring容器BeanFactory怎么使用

(XmlBeanDefinitionReader.detectValidationMode(resource) 方法 省略了catch處理部分代碼)

在上圖最后一個 try 塊調用了 XmlValidationModeDetector 類中的 detectValidationMode(inputStream) 方法做進一步處理,下面就看看這個方法(這里如果要全面了解,建議自己查看一遍源碼,畢竟在該方法中還調用了其他方法,也使用了幾個常量,這里并沒有列出)。

      Spring容器BeanFactory怎么使用

(XmlValidationModeDetector 類中的 detectValidationMode(inputStream) 方法)

上面獲取驗證模式部分需要根據(jù) DTD 和 XSD來進行理解,因為獲取驗證模式就是根據(jù)兩種驗證模式使用方法來的。Spring 檢測驗證模式的方法就是判斷是否包含 DOCTYPE,如果包含就是 DTD,否則就是 XSD(這一點從上面一張圖的第一行注釋就是可以看出:查看文件以查找 DOCTYPE),這一點從上圖方法中可以很容易的看出。

到這里,獲取驗證模式就講解完了。

 ? 獲取 Document

上面我們知道了在獲取 Document 之前要先獲取 XML 驗證模式。下面我們就來看看 Spring 中是怎么獲取 Document 的。在上面 (doLoadDocument() 方法)圖中我們看見 doLoadDocument 方法調用了本類 documentLoader 的 loadDocuemnt() 方法。documentLoader 定義如下:

private DocumentLoader documentLoader = new DefaultDocumentLoader();

DocumentLoader 是一個接口,所以使用其實現(xiàn)類 DefaultDocumentLoader;

先來看看 DefaultDocumentLoader 類中的 loadDocument() 方法吧。

      Spring容器BeanFactory怎么使用

(loadDocument() 方法)

上面這段代碼就是基本的 通過 SAX 解析 XML,這里算是基本步驟了。首先創(chuàng)建 DocumentBuilderFacotry 對象,再通過 DocumentBuilderFactory 創(chuàng)建 DocumentBuilder,然后解析 inputSource 來返回 Document 對象。這里涉及到了 XML 解析相關知識,可自行上網(wǎng)深入了解。

 ? 解析及注冊 BeanDefinitions

在上面 (doLoadBeanDefinitions() 方法) 圖中我們知道 獲取到了 Document 后,就執(zhí)行下面這行代碼:

return registerBeanDefinitions(doc, resource);

也就是 繼續(xù)調用 registerBeanDefinitions(doc, resource) 方法。

      Spring容器BeanFactory怎么使用
(registerBeanDefinitions(doc, resource) 方法)

上圖中第一行代碼就是創(chuàng)建 BeanDefinitionDocumentReader,BeanDefinitionDocumentReader 是接口,而實例化是在 createBeanDefinitionDocumentReader() 方法中完成的,而通過執(zhí)行此方法后,BeanDefinitionDocumentReader 真正的類型就是 DefaultBeanDefinitionDocumentReader (它的實現(xiàn)類)了。

上圖中第三行就是加載、注冊 Bean了,由于 BeanDefinitionDocumentReader 是接口,所以我們來到 DefaultBeanDefinitionDocumentReader 類中的 registerBeanDefinitions() 方法。

      Spring容器BeanFactory怎么使用

(registerBeanDefinitions(Document, XmlReaderContext) 方法)

上圖方法的重要目的之一就是提取 root,再將 root  作為參數(shù)繼續(xù) BeanDefinition 的注冊。

      Spring容器BeanFactory怎么使用

?。╠oRegisterBeanDefinitions(Element) 方法)

上圖代碼中涉及到 profile 屬性,該屬性詳情還請自行上網(wǎng)了解。上圖程序第二部分,程序會先獲取 beans 節(jié)點是否定義了 profile 屬性,如果定義了則需要到環(huán)境變量中區(qū)尋找,每定義就不解析。

處理了 profile 就可以開始進行 XML的讀取了,下面看看上圖框住的方法 parseBeanDefinitions(root, this.delegate)。

    Spring容器BeanFactory怎么使用

(parseBeanDefinitions(Element, BeanDefinitionParserDelegate) 方法)

在 Spring 的 XML文件中可以使用默認的 Bean聲明,也可以自定義。所以 Spring 針對不同的 Bean 聲明做了不同的處理。

到此,相信大家對“Spring容器BeanFactory怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

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

AI