Spring技術內幕:深入解析Spring架構與設計原理_第1頁
Spring技術內幕:深入解析Spring架構與設計原理_第2頁
Spring技術內幕:深入解析Spring架構與設計原理_第3頁
Spring技術內幕:深入解析Spring架構與設計原理_第4頁
Spring技術內幕:深入解析Spring架構與設計原理_第5頁
已閱讀5頁,還剩144頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

Spring技術內幕

深入解析Spring架構與設計原理(一)引子

緣起

已經很久沒有寫帖子了,現(xiàn)在總算是有點時間寫些東西,也算是對自己的一個記

錄吧。剛剛完成了一個軟件產品,從概念到運營都弄了一下,正在推廣當中,雖

然還沒有能夠達到盈虧平衡,但是這個過程,對自己也算是一種歷練。先不管結

果如何,好呆走過這么一遭了。

我打算用這個帖子,把自己在這個過程中的一些心得,特別是對Spring新的理

解,記錄下來。使用這個帖子的標題,持續(xù)下來。

簡單來說,自己的軟件產品是一個基于互聯(lián)網的SaaS協(xié)同軟件平臺,操作簡單,

支持流程定義,管理和多種客戶端-像短信,MSN,智能手機什么的(我這里

就不多做什么廣告了),也有一個企業(yè)版的版本,使用的技術框架是Hibernate

+Spring+Wicket,下面是Linux和MySQL,還有云計算的平臺的使用,以

支持其擴展性,雖然現(xiàn)在還沒有可擴展性的需求,但似乎不難從SaaS上,就會

想到云計算,其實,它們真的是天生的一對!

關于云計算啟己對這個技術很感興趣,覺得和開源軟件的結合,是很有意思的,

因為它們都有基于服務的基因,在云計算平臺的使用上,也有一些初步的實踐。

云計算是一個很有意思的話題,但在這里主要是想談Spring,所以對云計算,

這里就先不多說了,但非常歡迎有興趣的朋友和一起另外找地方討論!

回到正題,在我自己的產品中,其中除了Wicket和云計算外,其他都是大家非

常熟知的了,像Hibernate,Spring,MySQL什么的。在這個過程中,發(fā)現(xiàn)自己

對一些技術點也有了新的認識,最有體會的是Spring。當然,在這個過程中,

更大的收獲是對產品開發(fā)整個過程的認識,在這點上,真是一言難盡…??…

回到自己還算了解的Spring,這次我使用的是3.0的代碼,所以,有機會也把這

些代碼讀了幾遍,比原來的理解要加深了許多,也發(fā)現(xiàn)了不少和2.0代碼不同的

地方,以及自己一些對Spring的新的理解,這些,就讓我就用這個帖子系列,

給自己總結一下,也算是對自己以前的那個代碼分析的帖子做一個新的交代吧。

自己對Spring一點小小的見解

簡化Java企業(yè)應用的開發(fā),是Spring框架的目標.就是我們熟知的當年的那個

interface21,也亦非吳下阿蒙了,由它演進出來的Spring,以及由它帶來的嶄

新開發(fā)理念,也早已伴隨著這個開源框架的廣泛應用,而飛入尋常百姓家。與此

同時,伴隨著Spring的成熟,開源社區(qū)的成長,在Rod.Johnson的領導下,

以Spring為核心的一系列開源軟件的產品組合,其脈絡也逐漸的清晰和豐富起

來;現(xiàn)在,已經發(fā)展成為一個包括軟件運行,構建,部署運營,從而涵蓋整個

軟件服務生命周期的產品族群;同時也成為,在當今主流的軟件業(yè)態(tài)中,一個不

可或缺的重要組成。

在最近完成的VMware公司對Spring的運營者SpringSource公司的收購中,

也讓我們又看到了一個,在開源軟件中,蘊含著的巨大商業(yè)價值,以及又一次

基于開源模式的商業(yè)成功;也讓我們看到,Spring為自己設計的未來定位,它

與云計算的融合趨勢,以及,努力成為在云計算業(yè)態(tài)中,PaaS(PlatformAsa

Service)服務有力競爭者的戰(zhàn)略設想;由此,可以想象,在云計算這個全新的

計算時代中,如何秉承Spring的一貫風格,為云計算應用的開發(fā),提供高可

靠,高可用,高可擴展,高性能的應用平臺,對Spring團隊來說,是一個面臨

的全新挑戰(zhàn);在這個領域中的雄心和今后的作為,那就讓我們一起拭目以待吧。

這里也有點湊巧了,正好Spring和云計算都是自己喜歡的東西,說不定以后,

我還能夠在這兩者的結合上再寫些東西呢。

作為一個龐大的體系,Spring在Java企業(yè)應用中,和我們熟悉的企業(yè)應用服務

器一樣,比如我們熟知的其他產品,像Weblogic,Websphere,JBoss,.NET這些

等等,其定位和目的,都在于希望能夠起到一個企業(yè)應用資源的集成管理,以

及為應用開發(fā)提供平臺支持的作用,這和我們熟知的,像UNIX和Windows這

樣傳統(tǒng)意義上的操作系統(tǒng),在傳統(tǒng)的計算系統(tǒng)中,起到的作用非常的類似。只

不過按照個人的理解,它們不同在于,我們熟知的傳統(tǒng)操作系統(tǒng)關心的是存儲,

計算,通信,外圍設備這些物理資源的管理,并在管理這些資源的基礎上,為

應用程序提供一個統(tǒng)一平臺和服務接口;而像Spring這樣的應用平臺,它們關

心的是在Java企業(yè)應用中,對包括那些像Web應用,數據持久化,事務處理,

消息中間件,分布式計算等等這些,為企業(yè)應用服務的抽象資源的統(tǒng)一管理,并

在此基礎上,為應用提供一個基于POJO的開發(fā)環(huán)境。盡管各自面向的資源,

管理的對象,支持的應用以及使用的場景不同,但這兩者在整個系統(tǒng)中的定位,

卻依然有著可以類比和相互參考的地方,從某種意義上看,它們都起到一個資

源協(xié)調,平臺支持,以及服務集成的作用。

所以我覺得可以使用,我們看待傳統(tǒng)操作系統(tǒng)的方法和一些基本觀念,來對

Spring進行系統(tǒng)分析以及對Spring進行層次劃分,這樣可能更加容易理解,

同時,所以,個人感覺,仿照傳統(tǒng)操作系統(tǒng)的眼光,把對Spring框架的實現(xiàn),

劃分為核心,組件和應用這三個基本的層次,來理解Spring框架是不錯的一

個方法,就算是眾所周知的"三段論"的應用吧。不知道這種分析方法,是不是

太庸俗,但我自己還是覺得挺受用的,呵呵,誰叫我是個俗人呢!

今天先寫一些,就算是起個頭吧,明天繼續(xù)!寫寫IOC/AOP的一些具體東西。

深入解析Spring架構與設計原理(一)IOC實現(xiàn)原理

IOC的基礎

下面我們從IOC/AOP開始,它們是Spring平臺實現(xiàn)的核心部分;雖然,我們

一開始大多只是在這個層面上,做一些配置和外部特性的使用工作,但對這兩

個核心模塊工作原理和運作機制的理解,對深入理解Spring平臺,卻是至關重

要的;因為,它們同時也是Spring其他模塊實現(xiàn)的基礎。從Spring要做到的

目標,也就是從簡化JavaEE開發(fā)的出發(fā)點來看,簡單的來說,它是通過對POJO

開發(fā)的支持,來具體實現(xiàn)的;具體的說,Spring通過為應用開發(fā)提供基于POJO

的開發(fā)模式,把應用開發(fā)和復雜的JavaEE服務,實現(xiàn)解耦,并通過提高單元

測試的覆蓋率,從而有效的提高整個應用的開發(fā)質量。這樣一來,實際上,就需

要把為POJO提供支持的,各種JavaEE服務支持抽象到應用平臺中去,去封裝

起來;而這種封裝功能的實現(xiàn),在Spring中,就是由IOC容器以及AOP來具

體提供的,這兩個模塊,在很大程度上,體現(xiàn)了Spring作為應用開發(fā)平臺的

核心價值。它們的實現(xiàn),是RodJohnson在他的另一本著作《Expert

One-on-OneJ2EEDevelopmentwithoutEJB》中,所提到WithoutEJB設

計思想的體現(xiàn);同時也深刻的體現(xiàn)了Spring背后的設計理念。

從更深一點的技術層面上來看,因為Spring是一個基于Java語言的應用平臺,

如果我們能夠對Java計算模型,比如像JVM虛擬機實現(xiàn)技術的基本原理有一

些了解,會讓我們對Spring實現(xiàn)的理解,更加的深入,這些JVM虛擬機的特

性使用,包括像反射機制,代理類,字節(jié)碼技術等等。它們都是在Spring實

現(xiàn)中,涉及到的一些Java計算環(huán)境的底層技術;盡管對應用開發(fā)人員來說,可

能不會直接去涉及這些JVM虛擬機底層實現(xiàn)的工作,但是了解這些背景知識,

或多或少,對我們了解整個Spring平臺的應用背景有很大的幫助;打個比方來

說,就像我們在大學中,學習的那些關于計算機組織和系統(tǒng)方面的基本知識,

比如像數字電路,計算機組成原理,匯編語言,操作系統(tǒng)等等這些基本課程的學

習。雖然,坦率的來說,對我們這些大多數課程的學習者,在以后的工作中,

可能并沒有太多的機會,直接從事這么如此底層的技術開發(fā)工作;但具備這些知

識背景,為我們深入理解基于這些基礎技術構架起來的應用系統(tǒng),毫無疑問,是

不可缺少的。隨著JVM虛擬機技術的發(fā)展,可以設想到的是,更多虛擬機級別

的基本特性,將會持續(xù)的被應用平臺開發(fā)者所關注和采用,這也是我們在學習平

臺實現(xiàn)的過程中,非常值得注意的一點,因為這些底層技術實現(xiàn),毫無疑問,

會對Spring應用平臺的開發(fā)路線,產品策略產生重大的影響。同時,在使用

Spring作為應用平臺的時候,如果需要更深層次的開發(fā)和性能調優(yōu),這些底層

的知識,也是我們知識庫中不可缺少的部分。有了這些底層知識,理解整個系統(tǒng),

想來就應該障礙不大了。

IOC的一點認識

MSpringIOC的理解離不開對依賴反轉模式的理解,我們知道,關于如何反轉

對依賴的控制,把控制權從具體業(yè)務對象手中轉交到平臺或者框架中,是解決面

向對象系統(tǒng)設計復雜性和提高面向對象系統(tǒng)可測試性的一個有效的解決方案。

這個問題觸發(fā)了IoC設計模式的發(fā)展,是IoC容器要解決的核心問題。同時,

也是產品化的IoC容器出現(xiàn)的推動力。而我覺得Spring的IoC容器,就是一個

開源的實現(xiàn)依賴反轉模式的產品。

那具體什么是IoC容器呢?它在Spring框架中到底長什么樣?說了這么多,其

實對IoC容器的使用者來說,我們常常接觸到的BeanFactory和

Applicationcontext都可以看成是容器的具體表現(xiàn)形式。這些就是IoC容器,

或者說在Spring中提IoC容器,從實現(xiàn)來說,指的是一個容器系列。這也就

是說,我們通常所說的IoC容器,如果深入到Spring的實現(xiàn)去看,會發(fā)現(xiàn)IoC

容器實際上代表著一系列功能各異的容器產品。只是容器的功能有大有小,有

各自的特點。打個比方來說,就像是百貨商店里出售的商品,我們舉水桶為例子,

在商店中出售的水桶有大有小;制作材料也各不相同,有金屬的,有塑料的等

等,總之是各式各樣,但只要能裝水,具備水桶的基本特性,那就可以作為水桶

來出售來讓用戶使用。這在Spring中也是一樣,它有各式各樣的IoC容器的實

現(xiàn)供用戶選擇和使用;使用什么樣的容器完全取決于用戶的需要,但在使用之前

如果能夠了解容器的基本情況,那會對容器的使用是非常有幫助的;就像我們

在購買商品時進行的對商品的考察和挑選那樣。

我們從最基本的XmlBeanFactory看起,它是容器系列的最底層實現(xiàn),這個容

器的實現(xiàn)與我們在Spring應用中用到的那些上下文相比,有一個非常明顯的

特點,它只提供了最基本的IoC容器的功能。從它的名字中可以看出,這個IoC

容器可以讀取以XML形式定義的BeanDefinition.理解這一點有助于我們理

解Applicationcontext與基本的BeanFactory之間的區(qū)別和聯(lián)系。我們可以

認為直接的BeanFactory實現(xiàn)是IoC容器的基本形式,而各種

Applicationcontext的實現(xiàn)是IoC容器的高級表現(xiàn)形式。

仔細閱讀XmlBeanFactory的源碼,在一開始的注釋里面已經對

XmlBeanFactory的功能做了簡要的說明,從代碼的注釋還可以看到,這是Rod

Johnson在2001年就寫下的代碼,可見這個類應該是Spring的元老類了。它

是繼承DefaultListableBeanFactory這個類的,這個

DefaultListableBeanFactory就是一個很值得注意的容器!

Java代碼

1.publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{

2.privatefinalXmlBeanDefinitionReaderreader=newXmlBeanD

efinitionReader(this);

3.publicXmlBeanFactory(Resourceresource)throwsBeansExcept

ion{

4.this(resource,null);

5.)

6.publicXmlBeanFactory(Resourceresource,BeanFactoryparent

BeanFactory)throwsBeansException{

7.super(parentBeanFactory);

8.this.reader.loadBeanDefinitions(resource);

9.)

10.}

publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{

privatefinalXmlBeanDefinitionReaderreader=new

XmlBeanDefinitionReader(this);

publicXmlBeanFactory(Resourceresource)throws

BeansException{

this(resource,null);

)

publicXmlBeanFactory(Resourceresource,BeanFactory

parentBeanFactory)throwsBeansException{

super(parentBeanFactory);

this.reader.loadBeanDefinitions(resource);

)

)

XmlBeanFactory的功能是建立在DefaultListableBeanFactory這個基本容器

的基礎上的在這個基本容器的基礎上實現(xiàn)了其他諸如XML讀取的附加功能。

對于這些功能的實現(xiàn)原理,看一看XmlBeanFactory的代碼實現(xiàn)就能很容易地

理解。在如下的代碼中可以看到,在XmlBeanFactory構造方法中需要得到

Resource對象。對XmlBeanDefinitionReader對象的初始化,以及使用這個

這個對象來完成loadBeanDefinitions的調用,就是這個調用啟動了從

Resource中載入BeanDefinitions的過程,這個loadBeanDefinitions同時

也是IoC容器初始化的重要組成部分。

簡單來說,IoC容器的初始化包括BeanDefinition的Resouce定位、載入和注

冊這三個基本的過程。我覺得重點是在載入和對BeanDefinition做解析的這個

過程??梢詮腄efaultListableBeanFactory來入手看看IoC容器是怎樣完成

BeanDefinition載入的。在refresh調用完成以后,可以看到loadDefinition

的調用:

Java代碼

1.publicabstractclassAbstractXmlApplicationContextextendsAbst

ractRefreshableConfigApplicationContext{

2.publicAbstractXmlApplicationContextO{

3.)

4.publicAbstractXmlApplicationContext(ApplicationContextpare

nt){

5.super(parent);

6.)

7.〃這里是實現(xiàn)loadBeanDefinitions的地方

8.protectedvoidloadBeanDefinitions(DefaultListableBeanFactory

beanFactory)throwslOException{

9.//CreateanewXmlBeanDefinitionReaderforthegivenBean

Factory.

10.//創(chuàng)建XmlBeanDefinitionReader,并通過回調設置

到BeanFactory中去,創(chuàng)建BeanFactory的使用的也

DefaultListableBeanFactoryo

11.XmlBeanDefinitionReaderbeanDefinitionReader=newXmlB

eanDefinitionReader(beanFactory);

12.

13.//Configurethebeandefinitionreaderwiththiscontext's

14.//resourceloadingenvironment.

15.〃這里設置XmlBeanDefinitionReader,為

XmlBeanDefinitionReader酉己置ResourceLoader,因為

DefaultResourceLoader是父類,所以this可以直接被使用

16.beanDefinitionReader.setResourceLoader(this);

17.beanDefinitionReader.setEntityResolver(newResourceEntityR

esolver(this));

18.

19.//Allowasubclasstoprovidecustominitializationoftherea

der,

20.//thenproceedwithactuallyloadingthebeandefinitions.

21.〃這是啟動Bean定義信息載入的過程

22.initBeanDefinitionReader(beanDefinitionReader);

23.loadBeanDefinitions(beanDefinitionReader);

24.)

25.

26.protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionRea

derbeanDefinitionReader){

27.}

publicabstractclassAbstractXmlApplicationContextextends

AbstractRefreshableConfigApplicationContext{

publicAbstractXmlApplicationContextQ{

)

publicAbstractXmlApplicationContext(ApplicationContext

parent){

super(parent);

)

〃這里是實現(xiàn)loadBeanDefinitions的地方

protectedvoidloadBeanDefinitions(DefaultListableBeanFactory

beanFactory)throwslOException{

//CreateanewXmlBeanDefinitionReaderforthegiven

BeanFactory.

//創(chuàng)建XmlBeanDefinitionReader,并通過回調設置到

BeanFactory中去,創(chuàng)建BeanFactory的使用的也是

DefaultListableBeanFactoryo

XmlBeanDefinitionReaderbeanDefinitionReader=new

XmlBeanDefinitionReader(beanFactory);

//Configurethebeandefinitionreaderwiththis

context's

//resourceloadingenvironment.

〃這里設置XmlBeanDefinitionReader,為

XmlBeanDefinitionReader酉己置ResourceLoader,因為

DefaultResourceLoader是父類,所以this可以直接被使用

beanDefinitionReader.setResourceLoader(this);

beanDefinitionReader.setEntityResolver(new

ResourceEntityResolver(this));

//Allowasubclasstoprovidecustominitializationofthe

reader,

//thenproceedwithactuallyloadingthebean

definitions.

//這是啟動Bean定義信息載入的過程

initBeanDefinitionReader(beanDefinitionReader);

loadBeanDefinitions(beanDefinitionReader);

)

protectedvoid

initBeanDefinitionReader(XmlBeanDefinitionReader

beanDefinitionReader){

)

這里使用XmlBeanDefinitionReader來載入BeanDefinition至!]容器中,如以

下代碼清單所示:

Java代碼

1.〃這里是調用的入口。

2.publicintloadBeanDefinitions(Resourceresource)throwsBean

DefinitionStoreException{

3.returnloadBeanDefinitions(newEncodedResource(resource))

/

4.)

5.〃這里是載入XML形式的BeanDefinition的地方。

6.publicintloadBeanDefinitions(EncodedResourceencodedReso

urce)throwsBeanDefinitionStoreException{

7.Assert.notNull(encodedResource,"EncodedResourcemustn

otbenull");

8.if(logger.isInfoEnabled()){

9.("LoadingXMLbeandefinitionsfrom"+encod

edResource.getResource());

10.}

11.

12.Set<EncodedResource>currentResources=this.resourcesC

urrentlyBeingLoaded.get();

13.if(currentResources==null){

14.currentResources=newHashSet<EncodedResource>(4);

15.this.resourcesCurrentlyBeingLoaded.set(currentResources);

16.}

17.if(!currentResources.add(encodedResource)){

18.thrownewBeanDefinitionStoreException(

19."Detectedrecursiveloadingof"+encodedResource

+"-checkyourimportdefinitions!");

20.)

21.〃這里得到XML文件,并得到10的Inputsource準備進行讀取。

22.try{

23.Inputstreaminputstream=encodedResource.getResourc

e().getInputStream();

24.try{

25.InputSourceinputSource=newInputSource(inputStrea

m);

26.if(encodedResource.getEncodingO!=null){

27.inputSource.setEncoding(encodedResource.getEncod

ingO);

28.}

29.returndoLoadBeanDefinitions(inputSource,encodedRe

source.getResource());

30.)

31.finally{

32.inputStream.closeO;

33.)

34.)

35.catch(lOExceptionex){

36.thrownewBeanDefinitionStoreException(

37."lOExceptionparsingXMLdocumentfrom"+encod

edResource.getResource(),ex);

38.)

39.finally{

40.currentResources.remove(encodedResource);

41.if(currentResources.isEmptyO){

42.this.resourcesCurrentlyBeingLoaded.set(null);

43.)

44.)

45.}

46.〃具體的讀取過程可以在doLoadBeanDefinitions方法中找到:

47.〃這是從特定的XML文件中實際載入BeanDefinition的地方

48.protectedintdoLoadBeanDefinitions(InputSourceinputSource,

Resourceresource)

49.throwsBeanDefinitionStoreException{

50.try{

51.intvalidationMode=getValidationModeForResource(reso

urce);

52.〃這里取得XML文件的Document對象,這個解析過程是

由documentLoader完成的,這個documentLoader是

DefaultDocumentLoader,在定義documentLoader的地方創(chuàng)建

53.Documentdoc=this.documentLoader.loadDocument(

54.inputSource,getEntityResolver(),this.errorHandler,va

lidationMode,isNamespaceAwareO);

55.〃這里啟動的是對BeanDefinition解析的詳細過程,這個解析會

使用到Spring的Bean配置規(guī)則,是我們下面需要詳細關注的地方。

56.returnregisterBeanDefinitions(doc,resource);

57.)

58.catch(BeanDefinitionStoreExceptionex){

59.throwex;

60.)

61.catch(SAXParseExceptionex){

62.thrownewXmlBeanDefinitionStoreException(resource.get

DescriptionO,

63."Line"+ex.getLineNumber()+"inXMLdocumentfr

om"+resource+"isinvalid",ex);

64.)

65.catch(SAXExceptionex){

66.thrownewXmlBeanDefinitionStoreException(resource.get

DescriptionO,

67."XMLdocumentfrom"+resource+"isinvalid",ex);

68.)

69.catch(ParserConfigurationExceptionex){

70.thrownewBeanDefinitionStoreException(resource.getDes

criptionO,

71."ParserconfigurationexceptionparsingXMLfrom"

+resource,ex);

72.)

73.catch(lOExceptionex){

74.thrownewBeanDefinitionStoreException(resource.getDes

criptionO,

75."lOExceptionparsingXMLdocumentfrom"+resour

ce,ex);

76.)

77.catch(Throwableex){

78.thrownewBeanDefinitionStoreException(resource.getDes

criptionO,

79."UnexpectedexceptionparsingXMLdocumentfrom

"+resource,ex);

80.)

81.)

〃這里是調用的入口。

publicintloadBeanDefinitions(Resourceresource)throws

BeanDefinitionStoreException{

returnloadBeanDefinitions(new

EncodedResource(resource));

)

〃這里是載入XML形式的BeanDefinition的地方。

publicintloadBeanDefinitions(EncodedResource

encodedResource)throwsBeanDefinitionStoreException{

Assert.notNull(encodedResource,"EncodedResource

mustnotbenull");

if(logger.isInfoEnabledO){

(nLoadingXMLbeandefinitionsfrom

"+encodedResource.getResource());

)

Set<EncodedResource>currentResources=

this.resourcesCurrentlyBeingLoaded.get();

if(currentResources==null){

currentResources=new

HashSet<EncodedResource>(4);

this.resourcesCurrentlyBeingLoaded.set(currentResources);

)

if(!currentResources.add(encodedResource)){

thrownewBeanDefinitionStoreException(

"Detectedrecursiveloadingof"

+encodedResource+--checkyourimportdefinitions!");

)

〃這里得到XML文件,并得到10的Inputsource準備進行讀

取。

try(

Inputstreaminputstream=

encodedResource.getResource().getInputStream();

try(

InputSourceinputSource=new

InputSource(inputStream);

if(encodedResource.getEncodingO!=

null){

inputSource.setEncoding(encodedResource.getEncodingO);

)

return

doLoadBeanDefinitions(inputSource,encodedResource.getResourceO);

)

finally{

inputStream.closeO;

)

)

catch(lOExceptionex){

thrownewBeanDefinitionStoreException(

"lOExceptionparsingXML

documentfrom"+encodedResource.getResource(),ex);

)

finally{

currentResources.remove(encodedResource);

if(currentResources.isEmptyO){

this.resourcesCurrentlyBeingLoaded.set(null);

)

)

)

〃具體的讀取過程可以在doLoadBeanDefinitions方法中找到:

〃這是從特定的XML文件中實際載入BeanDefinition的地方

protectedintdoLoadBeanDefinitions(InputSourceinputSource,

Resourceresource)

throwsBeanDefinitionStoreException{

try{

intvalidationMode=

getValidationModeForResource(resource);

〃這里取得XML文件的Document對象,這個解析

過程是由documentLoader完成的,這個documentLoader是

DefaultDocumentLoader,在定義documentLoader的地方創(chuàng)建

Documentdoc=

this.documentLoader.loadDocument(

inputSource,getEntityResolverO,

this.errorHandler,validationMode,isNamespaceAwareO);

〃這里啟動的是對BeanDefinition解析的詳細過程,

這個解析會使用到Spring的Bean配置規(guī)則是我們下面需要詳細關注的地方。

returnregisterBeanDefinitions(doc,resource);

)

catch(BeanDefinitionStoreExceptionex){

throwex;

)

catch(SAXParseExceptionex){

thrownew

XmlBeanDefinitionStoreException(resource.getDescription(),

"Line"+ex.getLineNumber()+

inXMLdocumentfrom"+resource+"isinvalid",ex);

)

catch(SAXExceptionex){

thrownew

XmlBeanDefinitionStoreException(resource.getDescription(),

"XMLdocumentfrom"+

resource+"isinvalid",ex);

)

catch(ParserConfigurationExceptionex){

thrownew

BeanDefinitionStoreException(resource.getDescription(),

"Parserconfigurationexception

parsingXMLfrom"+resource,ex);

)

catch(lOExceptionex){

thrownew

BeanDefinitionStoreException(resource.getDescription(),

"lOExceptionparsingXML

documentfrom"+resource,ex);

)

catch(Throwableex){

thrownew

BeanDefinitionStoreException(resource.getDescription(),

"Unexpectedexceptionparsing

XMLdocumentfrom"+resource,ex);

)

)

關于具體的SpringBeanDefinition的解析,是在

BeanDefinitionParserDelegate中完成的。這個類里包含了各種SpringBean

定義規(guī)則的處理,感興趣的同學可以仔細研究。我們舉一個例子來分析這個處理

過程比如我們最熟悉的對Bean元素的處理是怎樣完成的也就是我們在XML

定義文件中出現(xiàn)的<bean></bean>這個最常見的元素信息是怎樣被處理的。

在這里,我們會看到那些熟悉的BeanDefinition定義的處理,比如id、name、

aliase等屬性元素。把這些元素的值從XML文件相應的元素的屬性中讀取出來

以后,會被設置到生成的BeanDefinitionHolder中去。這些屬性的解析還是

比較簡單的。對于其他元素配置的解析,比如各種Bean的屬性配置,通過一

個較為復雜的解析過程,這個過程是由parseBeanDefinitionElement來完成的。

解析完成以后,會把解析結果放到BeanDefinition對象中并設置到

BeanDefinitionHolder中去,如以下清單所示:

Java代碼

1.publicBeanDefinitionHolderparseBeanDefinition日ement(日emen

tele,BeanDefinitioncontainingBean){

2.〃這里取得在<bean>元素中定義的id、name和aliase屬性的值

3.Stringid=ele.getAttribute(ID_ATTRIBUTE);

4.StringnameAttr=ele.getAttribute(NAME_ATTRIBUTE);

5.

6.List<String>aliases=newArrayList<String>();

7.if(Stringlltils.hasLength(nameAttr)){

8.String[]nameArr=Stringlltils.tokenizeToStringArray(nam

eAttr,BEAN_NAME_DELIMITERS);

9.aliases.addAII(Arrays.asList(nameArr));

10.)

11.

12.StringbeanName=id;

13.if(!Stringlltils.hasText(beanName)&&!aliases.isEmpty()){

14.beanName=aliases.remove(O);

15.if(logger.isDebugEnabled()){

16.logger.debug("NoXML'id'specified-using,n+beanN

ame+

17.asbeannameand"+aliases+"asaliases");

18.)

19.)

20.

21.if(containingBean==null){

22.checkNamellniqueness(beanName,aliases,ele);

23.)

24.

25.〃這個方法會引發(fā)對bean元素的詳細解析

26.AbstractBeanDefinitionbeanDefinition=parseBeanDefinition日e

ment(ele,beanName,containingBean);

27.if(beanDefinition!=null){

28.if(!Stringlltils.hasText(beanName)){

29.try{

30.if(containingBean!=null){

31.beanName=BeanDefinitionReaderlltils.generateB

eanName(

32.beanDefinition,this.readerContext.getRegistry

0,true);

33.)

34.else{

35.beanName=this.readerContext.generateBeanNa

me(beanDefinition);

36.//Registeranaliasfortheplainbeanclassname,if

st川possible,

37.//ifthegeneratorreturnedtheclassnameplusas

uffix.

38.//ThisisexpectedforSpring1.2/2.0backwardsco

mpatibility.

39.StringbeanClassName=beanDefinition.getBeanCI

assName();

40.if(beanClassName!=null&&

41.beanName.startsWith(beanClassName)&&b

eanName.lengthQ>beanClassName.length()&&

42.!this.readerContext.getRegistry().isBeanNameI

nllse(beanClassName)){

43.aliases.add(beanClassName);

44.)

45.)

46.if(logger.isDebugEnabledO){

47.logger.debug("NeitherXML'id'nor'name'specifie

d-

48."usinggeneratedbeanname["+beanName

+T);

49.)

50.}

51.catch(Exceptionex){

52.error(ex.getMessage(),ele);

53.returnnull;

54.)

55.)

56.String[]aliasesArray=StringUtils.toStringArray(aliases);

57.returnnewBeanDefinitionHolder(beanDefinition,beanNa

me,aliasesArray);

58.)

59.

60.returnnull;

61.)

publicBeanDefinitionHolderparseBeanDefinition日ement(日ementele,

BeanDefinitioncontainingBean){

〃這里取得在<bean>元素中定義的id、name和aliase屬性

的值

Stringid=ele.getAttribute(ID_ATTRIBUTE);

StringnameAttr=ele.getAttribute(NAME_ATTRIBUTE);

List<String>aliases=newArrayList<String>();

if(StringUtils.hasLength(nameAttr)){

String[]nameArr=

Stringlltils.tokenizeToStringArray(nameAttr,BEAN_NAME_DELIMITERS);

aliases.addAII(Arrays.asList(nameArr));

)

StringbeanName=id;

if(!Stringlltils.hasText(beanName)&&!aliases.isEmpty())

(

beanName=aliases.remove(O);

if(logger.isDebugEnabledO){

logger.debug(nNoXML'id'specified-

using+beanName+

asbeannameand"+

aliases+"asaliases");

)

)

if(containingBean==null){

checkNamellniqueness(beanName,aliases,ele);

)

〃這個方法會引發(fā)對bean元素的詳細解析

AbstractBeanDefinitionbeanDefinition=

parseBeanDefinitionElement(ele,beanName,containingBean);

if(beanDefinition!=null){

if(!Stringlltils.hasText(beanName)){

try(

if(containingBean!=null){

beanName=

BeanDefinitionReaderlltils.generateBeanName(

beanDefinition,this.readerContext.getRegistryO,true);

)

else{

beanName=

this.readerContext.generateBeanName(beanDefinition);

//Registeranaliasfor

theplainbeanclassname,ifstillpossible,

//ifthegenerator

returnedtheclassnameplusasuffix.

//Thisisexpectedfor

Spring1.2/2.0backwardscompatibility.

StringbeanClassName

=beanDefinition.getBeanClassName();

if(beanClassName!=

null&&

beanName.startsWith(beanClassName)&&beanName.length()>

beanClassName.length()&&

!this.readerContext.getRegistry().isBeanNameInllse(beanClassN

ame)){

aliases.add(beanClassName);

)

)

if(logger.isDebugEnabled()){

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論