本篇內(nèi)容主要講解“Spring容器BeanFactory怎么使用”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Spring容器BeanFactory怎么使用”吧!
成都創(chuàng)新互聯(lián)專注于企業(yè)成都全網(wǎng)營(yíng)銷推廣、網(wǎng)站重做改版、白堿灘網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為白堿灘等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
Spring容器是Spring的核心,它可以創(chuàng)建對(duì)象,把他們關(guān)聯(lián)在一起,配置各個(gè)對(duì)象,并管理每個(gè)對(duì)象的整個(gè)生命周期。Spring容器使用依賴注入(DI)來(lái)管理組成一個(gè)應(yīng)用程序的組件。這些對(duì)象被稱為Spring Beans (一個(gè)對(duì)象就是一個(gè)Bean)。
Spring中有兩種容器:
① BeanFactory 一個(gè)最簡(jiǎn)單的Spring容器,給依賴注入(DI)提供了基礎(chǔ)的支持。
② ApplicationContext 此容器添加以一些企業(yè)需要用到的東西,更加全面。它包含了BeanFactory容器中的東西。
在Spring中,有大量BeanFactory接口的實(shí)現(xiàn)類(見(jiàn)下圖),但是,最常用的也就是XmlBeanFactory類(在Eclipse中,查看其源碼可以看見(jiàn)已經(jīng)是一個(gè)過(guò)時(shí)的類了,但我們也需要了解。),它可以從一個(gè) XML 文件中讀取配置元數(shù)據(jù),由這些元數(shù)據(jù)來(lái)生成一個(gè)被配置化的系統(tǒng)或者應(yīng)用。
(BeanFactory接口實(shí)現(xiàn)類)
本文主要是針對(duì)下面一行代碼執(zhí)行所發(fā)生的事情的一些深入探究。
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("配置文件"));
Ⅰ. DefaultListableBeanFactory
XmlBeanFactory類繼承自DefaultListableBeanFacotry類,而DefaultListableBeanFactory類是Bean加載的核心部分,是Spring注冊(cè)及加載Bean的默認(rèn)實(shí)現(xiàn)。
XmlBeanFactory類與DefaultListableBeanFactory類之間不同的地方就在于XmlBeanFactory類中使用了自定義的XML讀取器XmlBeanDefinitionReader,
(XmlBeanDefinitionReader對(duì)象)
實(shí)現(xiàn)了個(gè)性化的BeanDefinitionReader讀取,DefaultListableBeaFactory類繼承了AbstractAutoWireCapableBeanFactory類,并實(shí)現(xiàn)了ConfigurableListableBeanFactory以及BeanDefinitionRegistry接口。
(DefaultListableBeanFactory類)
DefaultListableBeanFactory類的基類,實(shí)現(xiàn)接口的一些相關(guān)類圖:
(容器加載部分相關(guān)類圖)
XmlBeanFactory類就繼承自DefaultListableBeanFactory類。XmlBeanFactory類對(duì)DefaultListableBeanFactory類進(jìn)行了擴(kuò)展,在XMLBeanFactory中主要使用reader屬性對(duì)資源文件進(jìn)行讀取和注冊(cè)。
XmlBeanFactory類的構(gòu)造方法如下圖:
(XmlBeanFactory構(gòu)造方法)
Ⅱ. XmlBeanDefinitionReader
上面我們已經(jīng)知道了XmlBeanFactory類和DefaultListableBeanFactory類的區(qū)別了,XmlBeanFactory類中定義了一個(gè)XmlBeanDefinitionReader對(duì)象,用于對(duì)資源文件進(jìn)行處理。
XML配置文件的讀取對(duì)于Spring而言非常重要,因?yàn)镾pring絕大部分功能都是以配置文件作為切入點(diǎn)的,那么,我們就要從XmlBeanDefinitionReader類中梳理一下資源文件讀取、解析和注冊(cè)的大致流程。
(配置文件讀取相關(guān)類)
通過(guò)上面配置文件讀取相關(guān)類圖可以得到讀取大致流程如下:
① 通過(guò)繼承自 AbstratcBeanDefinitionReader 中的方法,來(lái)使用 ResourceLoader 將資源文件路徑轉(zhuǎn)換為對(duì)應(yīng)的 Resource 文件。
② 通過(guò) DocumentLoader 對(duì) Resource 文件進(jìn)行轉(zhuǎn)換,將 Resource 文件轉(zhuǎn)換為 Document 文件。
③ 通過(guò) DefaultBeanDefinitionDocumentReader 類對(duì)Document進(jìn)行解析,并使用 BeanDefinitionParserDelegate 對(duì) Element 進(jìn)行解析。
上述三步只是讀取配置文件的一個(gè)大致流程,接下來(lái)將進(jìn)行更加詳細(xì)的解析。
上面我們已經(jīng)知道了 XmlBeanFacotry 和 DefaultListableBeanFactory 的區(qū)別了。XmlBeanFactory 結(jié)構(gòu)如下圖:
(XmlBeanFactory類結(jié)構(gòu))
在Spring中,我們創(chuàng)建了一個(gè)配置文件,并且在配置文件中配置了一個(gè)Bean后,那么,我們就要獲取這個(gè)Bean。在測(cè)試代碼中我們都寫過(guò)這樣一句代碼:
XmlBeanFactory xmlBeanFactory = new XmlBeanFacotry(new ClassPathResource("配置文件"));
也可以是:
BeanFactory beanFactory = new XmlBeanFacotry(new ClassPathResource("配置文件"));
總之,以上兩句行代碼就是讀取配置文件創(chuàng)建容器。
那么,new XmlBeanFacotry(new ClassPathResource("配置文件")) 這句代碼到底是怎么回事呢?先看看下面的 XmlBeanFactory 初始化時(shí)序圖吧!(畫得不好,將就看吧)
(XmlBeanFactory初始化時(shí)序圖)
時(shí)序圖解析:
◆ 首先,時(shí)序圖從一個(gè)測(cè)試類開(kāi)始,這個(gè)測(cè)試類就是上面創(chuàng)建 XmlBeanFactory 那里。
◆ 創(chuàng)建 XmlBeanFactory 需要一個(gè) Resource 對(duì)象,由于 Resource 是接口,所以我們使用其實(shí)現(xiàn)類 ClassPathResource 來(lái)構(gòu)造 Resource 資源文件的實(shí)例對(duì)象。
◆ 有了 Resource 對(duì)象就可以進(jìn)行 XmlBeanFactory 的初始化了,最后得到一個(gè) BeanFactory。
那么,問(wèn)題來(lái)了,什么又是 Resource呢?它是怎么對(duì)資源進(jìn)行封裝處理的呢?
● Resource 是什么
在說(shuō) Resource 之前,我們要知道一個(gè)接口:InputStreamSource,該接口封裝任何能返回 InputStream 的類,比如File、Classpath下的資源、Byte、Array等。它只定義了一個(gè)方法:InputStream getInputStream() throws IOException; 該方法返回一個(gè) InputStream 對(duì)象。
Resource 接口抽象了所有 Spring 內(nèi)部所使用到的底層資源: File、URL、Classpath等。Resource 接口中的方法及大致作用如下圖:
(Resource接口)
對(duì)于不同來(lái)源的資源文件都有對(duì)象的 Resource 實(shí)現(xiàn):
文件(FileSystemResource)、Classpath資源(ClassPathResource)、URL資源(UrlResource)等。
(資源文件處理部分相關(guān)類)
資源文件的加載在日常開(kāi)發(fā)中也經(jīng)常被使用,可以直接使用 Spring 提供的類,如在加載文件時(shí)使用如下代碼:
Resource resource = new ClassPathResource("資源文件");
InputStream inputStream = resource.getInputStream();
得到 inputStream 后,我們就可以按照以往的開(kāi)發(fā)方式進(jìn)行開(kāi)發(fā)了,而且還可以使用 Resource 及其實(shí)現(xiàn)類的一些東西。
當(dāng)通過(guò) Resource 相關(guān)類完成了對(duì)配置文件的封裝后,配置文件的讀取就是 XmlBeanDefinitionReader 來(lái)完成了。
現(xiàn)在我們已經(jīng)知道了 Spring 中將配置文件封裝為 Resource 對(duì)象,下面繼續(xù)了解 XmlBeanFactory 的初始化過(guò)程。從上面 XmlBeanFactory類結(jié)構(gòu)圖中可以看出 XMLBeanFactory 類共有兩個(gè)構(gòu)造方法,如下圖:
(XmlBeanFactory類構(gòu)造方法)
從上圖我們看出,第一個(gè)構(gòu)造方法內(nèi)部調(diào)用了該類內(nèi)部的另一個(gè)構(gòu)造方法。所以,我們也就了解第二個(gè)構(gòu)造方法了。
首先,在第一行出現(xiàn)了 super(parentBeanFactory) 這樣一句代碼,調(diào)用了父類(DefaultListableBeanFactory)的一個(gè)構(gòu)造方法。
(DefaultListableBeanFactory有參構(gòu)造方法)
來(lái)到父類構(gòu)造方法,我們發(fā)現(xiàn)又繼續(xù)調(diào)用了父類(AbstractAutowireCapableBeanFactory)的構(gòu)造方法,見(jiàn)下圖:
(AbstractAutowireCapableBeanFactory類構(gòu)造方法)
從圖中可以看出,有參構(gòu)造方法(我們使用的就是有參構(gòu)造)先調(diào)用了本類中的一個(gè)無(wú)參構(gòu)造方法,無(wú)參構(gòu)造方法首先執(zhí)行了父類(AbstractBeanFactory)的構(gòu)造方法(一個(gè)空方法),這里了解一下 ignoreDependencyInterface 方法,該方法的主要功能就是 忽略自動(dòng)連接給定的依賴接口(忽略給定接口的自動(dòng)裝配功能)。那么,該方法有什么用?
如:當(dāng) A類 中有屬性 B,當(dāng) Spring 在獲取 A 的 Bean 的時(shí)候如果屬性 B 還沒(méi)有被初始化,Spring 就會(huì)自動(dòng)初始化 B,(這也是Spring的一個(gè)重要特性)。但是,某些情況下,B 不會(huì)被初始化,比如 B 實(shí)現(xiàn)了 BeanNameAware 接口。Spring API介紹:應(yīng)用程序上下文通常使用它來(lái)注冊(cè)以其他方式解析的依賴項(xiàng),如通過(guò)BeanFactoryAware實(shí)現(xiàn)的BeanFactory或通過(guò)ApplicationContextAware實(shí)現(xiàn)的ApplicationContext。默認(rèn)情況下,只忽略BeanFactoryAware接口。若要忽略其他類型,請(qǐng)為每個(gè)類型調(diào)用此方法。
最后調(diào)用 setParentBeanFactory 方法設(shè)置 BeanFactory對(duì)象。
(setParentBeanFactory方法)
在 setParentBeanFactory 方法中有一個(gè) if 判斷,用于判斷是否已經(jīng)關(guān)聯(lián)了 BeanFactory,如果已經(jīng)關(guān)聯(lián)就拋出異常。
? 加載Bean
在上面講到 Resource 時(shí),我們知道了 XmlBeanFactory 的構(gòu)造方法,我們也知道了其中一個(gè)構(gòu)造方法首先調(diào)用了父類的構(gòu)造方法,那么,在super()語(yǔ)句下面就是 this.reader.loadBeanDefinitions(resource) 方法的調(diào)用。這個(gè)方法才是整個(gè)資源加載的切入點(diǎn),下面是該方法調(diào)用的時(shí)序圖:
(loadBeanDefinitions方法執(zhí)行時(shí)序圖)
從上圖可以看到,這個(gè)方法的調(diào)用引起了很大一串的工作。然而這些工作也只是在做準(zhǔn)備工作,下面說(shuō)說(shuō)這里究竟在準(zhǔn)備什么工作:
(1)封裝資源文件。當(dāng)調(diào)用 loadBeanDefinitions 方法時(shí),就會(huì)跳轉(zhuǎn)到該方法中,該方法就調(diào)用了本類的一個(gè)重載方法,同時(shí)根據(jù) Resource 對(duì)象創(chuàng)建一個(gè)EncodedResource 對(duì)象作為參數(shù)傳遞,使用 EncodedResource 的作用就是把 Resource 使用 EncodedResource 類進(jìn)行封裝。
(loadBeanDefinitions(Resource resource)方法)
(2)獲取輸入流構(gòu)建 inputSource。從 Resource 中獲取對(duì)應(yīng)的 InputStream 并創(chuàng)建 InputSource。
(loadBeanDefinitions(EncodedResource encodedResource)方法中 獲取 InputStream 并 創(chuàng)建 InputSource)
(3)通過(guò)剛剛創(chuàng)建的 InputSource 對(duì)象和 Resource繼續(xù)調(diào)用 doLoadBeanDefinitions()方法。
(doLoadBeanDefinitions(InputSource, Resource)方法調(diào)用)
上面,我們多次看到 EncodedResource ,那么,它到底是什么?
? EncodedResource
通過(guò)名字可以猜測(cè)該類和編碼相關(guān)。該類主要就是對(duì)資源文件的編碼進(jìn)行處理的。其中一個(gè)很重要的方法 getReader() 方法 ,當(dāng)設(shè)置了編碼屬性時(shí),Spring 就會(huì)使用相應(yīng)的編碼作為輸入流的編碼。
首先看看它的一個(gè)構(gòu)造方法:(該類一共有四個(gè)構(gòu)造方法,但其余三個(gè)構(gòu)造方法均調(diào)用了下面這個(gè)構(gòu)造方法)
(EncodedResource類的一個(gè)構(gòu)造方法)
該構(gòu)造方法主要就是對(duì)類中的屬性進(jìn)行初始化。
再來(lái)看看 getReader() 方法:
(getReader() 方法)
getReader() 方法構(gòu)造了一個(gè)含編碼的 InputStreamReader。將 Resource 封裝為 EncodedResource 對(duì)象后,就來(lái)到了 XmlBeanDefinitionReader 類中的 loadBeanDefinitions() 方法(另一個(gè)重載后的方法),也就是下圖中的方法。
(loadBeanDefinitions(EncodedResource ..)方法部分重要代碼)
上圖方法才算是真正的數(shù)據(jù)準(zhǔn)備,也就是往上第7張 時(shí)序圖中所描述的部分。
再次回顧以上數(shù)據(jù)準(zhǔn)備部分內(nèi)容,首先將傳入的 Resource 對(duì)象封裝為 EncodedResource,為什么需要封裝?目的是考慮到 Resource 可能存在編碼要求的情況,其次,通過(guò)SAX讀取XML文件的方式來(lái)準(zhǔn)備 InputSource對(duì)象,最后將準(zhǔn)備的數(shù)據(jù)通過(guò)參數(shù)傳遞給核心處理方法 doLoadBeanDefinitions(InputSource inputSource, Resource resource)。下面就來(lái)看看 doLoadBeanDefinitions() 方法做了什么事情:
(doLoadBeanDefinitions() 方法部分代碼(除catch部分))
doLoadBeanDefinitions() 方法 try 后面有多個(gè) catch ,除開(kāi)這些 catch,那么,這段代碼做了以下三件事情:
(1)獲取對(duì) XML 文件的驗(yàn)證模式
(2)加載 XML 文件,得到對(duì)應(yīng)的 Document 對(duì)象
(3)根據(jù)返回的 Document 對(duì)象注冊(cè) Bean 信息
以上三個(gè)操作支撐著整個(gè)Spring容器的實(shí)現(xiàn)基礎(chǔ),下面就將從這三個(gè)步驟講起。
? 獲取 XML的驗(yàn)證模式
XML 驗(yàn)證模式的作用:用于保證 XML 文件的正確性(貌似就是所說(shuō)的約束),常用的驗(yàn)證模式有兩種:DTD(Document Type Definition) 和 XSD(XML Schemas Definition)。詳細(xì)了解驗(yàn)證模式請(qǐng)自行上網(wǎng)搜索。
在上一張(doLoadBeanDefinitions方法代碼)圖中,我們看見(jiàn) try 塊中第一行代碼是: Document document = doLoadDocument(inputSource, resource); 調(diào)用了本類中的 doLoadDocument() 方法,但是,這句代碼主要是用來(lái)獲取 Document對(duì)象的,也就是上面第二件事情;但是,在其中會(huì)先完成對(duì) XML 文件驗(yàn)證模式的獲取。
(doLoadDocument() 方法)
我們可以從上圖看到,在 loadDocument() 方法執(zhí)行時(shí),先執(zhí)行了 getValidationModeForResource(resource) 方法,該方法返回一個(gè) int 類型的值。(在 Spring3.2 中,并不存在 doLoadDocument() 方法,是直接在 doLoadBeanDefintions() 方法中調(diào)用 getValidationModeForResource(resource) 方法 和 loadDocument() 方法),下面我們看看 getValidationModeForResource(resource) 方法做了什么事情:
(getValidationModeForResource(resource) 方法)
在上面方法中,使用了幾個(gè)常量,下圖是幾個(gè)常量所表示的值:
(org.springframework.util.xml.XmlValidationModeDetector類中的幾個(gè)常量)
注意:XmlBeanDefinitionsReader 類中也有上圖中除了 DOCTYPE 常量以外的幾個(gè) int 類型的同名的常量,其值就是上面的值。也就是 Spring 把不同的驗(yàn)證模式使用了不同數(shù)值表示了而已。
在往上第二張圖中得知 getValidationModeForResource(resource) 方法首先判斷是否手動(dòng)指定(通過(guò) setValidationMode() 方法設(shè)置驗(yàn)證模式)了驗(yàn)證模式,判斷方式就是 獲取 validationMode 屬性進(jìn)行判斷。否則使用自動(dòng)檢測(cè)的方式,自動(dòng)檢測(cè)調(diào)用了 org.springframework.beans.factory.xml.XmlBeanDefinitionReader.detectValidationMode(resource) 方法(本類中的方法)實(shí)現(xiàn)。
(XmlBeanDefinitionReader.detectValidationMode(resource) 方法 省略了catch處理部分代碼)
在上圖最后一個(gè) try 塊調(diào)用了 XmlValidationModeDetector 類中的 detectValidationMode(inputStream) 方法做進(jìn)一步處理,下面就看看這個(gè)方法(這里如果要全面了解,建議自己查看一遍源碼,畢竟在該方法中還調(diào)用了其他方法,也使用了幾個(gè)常量,這里并沒(méi)有列出)。
(XmlValidationModeDetector 類中的 detectValidationMode(inputStream) 方法)
上面獲取驗(yàn)證模式部分需要根據(jù) DTD 和 XSD來(lái)進(jìn)行理解,因?yàn)楂@取驗(yàn)證模式就是根據(jù)兩種驗(yàn)證模式使用方法來(lái)的。Spring 檢測(cè)驗(yàn)證模式的方法就是判斷是否包含 DOCTYPE,如果包含就是 DTD,否則就是 XSD(這一點(diǎn)從上面一張圖的第一行注釋就是可以看出:查看文件以查找 DOCTYPE),這一點(diǎn)從上圖方法中可以很容易的看出。
到這里,獲取驗(yàn)證模式就講解完了。
? 獲取 Document
上面我們知道了在獲取 Document 之前要先獲取 XML 驗(yàn)證模式。下面我們就來(lái)看看 Spring 中是怎么獲取 Document 的。在上面 (doLoadDocument() 方法)圖中我們看見(jiàn) doLoadDocument 方法調(diào)用了本類 documentLoader 的 loadDocuemnt() 方法。documentLoader 定義如下:
private DocumentLoader documentLoader = new DefaultDocumentLoader();
DocumentLoader 是一個(gè)接口,所以使用其實(shí)現(xiàn)類 DefaultDocumentLoader;
先來(lái)看看 DefaultDocumentLoader 類中的 loadDocument() 方法吧。
(loadDocument() 方法)
上面這段代碼就是基本的 通過(guò) SAX 解析 XML,這里算是基本步驟了。首先創(chuàng)建 DocumentBuilderFacotry 對(duì)象,再通過(guò) DocumentBuilderFactory 創(chuàng)建 DocumentBuilder,然后解析 inputSource 來(lái)返回 Document 對(duì)象。這里涉及到了 XML 解析相關(guān)知識(shí),可自行上網(wǎng)深入了解。
? 解析及注冊(cè) BeanDefinitions
在上面 (doLoadBeanDefinitions() 方法) 圖中我們知道 獲取到了 Document 后,就執(zhí)行下面這行代碼:
return registerBeanDefinitions(doc, resource);
也就是 繼續(xù)調(diào)用 registerBeanDefinitions(doc, resource) 方法。
(registerBeanDefinitions(doc, resource) 方法)
上圖中第一行代碼就是創(chuàng)建 BeanDefinitionDocumentReader,BeanDefinitionDocumentReader 是接口,而實(shí)例化是在 createBeanDefinitionDocumentReader() 方法中完成的,而通過(guò)執(zhí)行此方法后,BeanDefinitionDocumentReader 真正的類型就是 DefaultBeanDefinitionDocumentReader (它的實(shí)現(xiàn)類)了。
上圖中第三行就是加載、注冊(cè) Bean了,由于 BeanDefinitionDocumentReader 是接口,所以我們來(lái)到 DefaultBeanDefinitionDocumentReader 類中的 registerBeanDefinitions() 方法。
(registerBeanDefinitions(Document, XmlReaderContext) 方法)
上圖方法的重要目的之一就是提取 root,再將 root 作為參數(shù)繼續(xù) BeanDefinition 的注冊(cè)。
(doRegisterBeanDefinitions(Element) 方法)
上圖代碼中涉及到 profile 屬性,該屬性詳情還請(qǐng)自行上網(wǎng)了解。上圖程序第二部分,程序會(huì)先獲取 beans 節(jié)點(diǎn)是否定義了 profile 屬性,如果定義了則需要到環(huán)境變量中區(qū)尋找,每定義就不解析。
處理了 profile 就可以開(kāi)始進(jìn)行 XML的讀取了,下面看看上圖框住的方法 parseBeanDefinitions(root, this.delegate)。
(parseBeanDefinitions(Element, BeanDefinitionParserDelegate) 方法)
在 Spring 的 XML文件中可以使用默認(rèn)的 Bean聲明,也可以自定義。所以 Spring 針對(duì)不同的 Bean 聲明做了不同的處理。
到此,相信大家對(duì)“Spring容器BeanFactory怎么使用”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
文章題目:Spring容器BeanFactory怎么使用
文章位置:http://jinyejixie.com/article20/ghdojo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷推廣、虛擬主機(jī)、定制網(wǎng)站、小程序開(kāi)發(fā)、網(wǎng)站改版、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)