瘋狂java實戰(zhàn)演義源碼第14章自己開發(fā)ioc容器_第1頁
瘋狂java實戰(zhàn)演義源碼第14章自己開發(fā)ioc容器_第2頁
瘋狂java實戰(zhàn)演義源碼第14章自己開發(fā)ioc容器_第3頁
瘋狂java實戰(zhàn)演義源碼第14章自己開發(fā)ioc容器_第4頁
瘋狂java實戰(zhàn)演義源碼第14章自己開發(fā)ioc容器_第5頁
已閱讀5頁,還剩38頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

IoCnewnew這個類,就可以得到該實例呢?IoC的概念很好的幫助我們解決了這個問題,當(dāng)我們需要在一個類中使用另外的類時,可以通過一些配置來得到該類的實現(xiàn)。IoCInversionofControl簡稱,又稱控制反轉(zhuǎn),一搞清楚了控制反轉(zhuǎn)的概念后,我們再來了解什么叫依賴注入。依賴注入(DependencyInjection)那么可以在IoC容器中向該類注入需要被調(diào)用的實例。而不需要關(guān)注各個組件的依賴的關(guān)系。常用的IoCSpringIoC容器、webworkIoC容器、google-guice,apache的HiveMind等。一個整合的例子,來說明IoC容器給我們帶來什么樣的好處。機(jī)制可以讓我們動態(tài)的得到某個類型的屬性、構(gòu)造器和方法。Java的反射機(jī)制可以在運行時構(gòu)造某一這些實例設(shè)置相應(yīng)的屬性,因此我們需要使用Java的反射機(jī)制。們的IoC容器的配置文件,因此使用dom4j就非常的合適。JunitJava程序員編寫單元測試。在本章中,我們每編寫一個功能點,就如果站在XP(極限編程)的角度來講,編寫測試可以讓我們的代碼更加健壯,更不懼任何的變更,對果,我們當(dāng)前所使用的是Junit4。(beanbean是否為單態(tài),是否需要延遲加載定。確定了配置文件的內(nèi)容后,我們開始著手編寫DTD文件。聲明…個bean…與類型,這些我們的IoC容器得到這些配置后,就可以幫我們創(chuàng)建這些類的實例。具體的配置如下:以上的bean配置表示我們在IoC容器中創(chuàng)建了一個myDate的bean,該bean聲明單態(tài)的beanbean的時候,就重新創(chuàng)建一個。我們?yōu)閎ean的配置添加一個singleton屬性,用來聲明bean是否為單態(tài)。IoCbean,我們可以為配置文件提供一個屬性,讓容器知道我們在容器初始化的時候,是否需要創(chuàng)建。我們?yōu)閎ean提供一個lazy-init的屬性: myDatebean節(jié)點加了這個屬性后,beans節(jié)點也default-lazy-initbeanbeanlazy-initlazy-init屬性不顯式指定的話,可以使用false作為默認(rèn)值。<property<ref<property<ref<beanid="school"studentbeanschoolbean,這樣,school和屬性,propertyref子節(jié)點,refbean。除了注入另外定義的bean外,還可以向bean中注入一些普通的屬性:<property<value<ref<ref<valuestudentbeanStudent類提供一個構(gòu)Student<valueStudentbean<beanid="school"<beanid="school"studentautowirebyNamebean的名稱自動注入到studentStudentsetSchoolsetterSchoold對象,那么容器SchoolbeanStudentbeansdefault,那么就可以進(jìn)行自動裝配。<beans<beans<beanid="school"示不需要自動裝配。beanautowire屬性默認(rèn)值為default。的約束文件(DTD。簡單的說,DTD就是一種對XML文件定制的規(guī)范。<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD(bean*<!ATTLISTbeansdefault-lazy-init(true|false)<!ATTLISTbeansdefault-autowire(no|byName)指定bean<!ELEMENTbean(constructor-arg|指定bean<!ATTLISTbeanidCDATA<!ATTLISTbeanclassCDATA<!ATTLISTbeanlazy-init(true|false|default)<!ATTLISTbeansingleton(true|false)<!ATTLISTbeanautowire(no|byName|default)<!ELEMENTconstructor-arg((ref|value|null)聲明property<!ELEMENT((ref|value|聲明property<!ATTLISTpropertynameCDATA聲明property<!ATTLISTvaluetypeCDATAref<!ELEMENTref<!ATTLISTrefbeanCDATA聲明value認(rèn)值(不需要顯式提供)為false和no。bean節(jié)點:beansbean節(jié)點,beanidclass屬性,可以值,autowire屬性的默認(rèn)值是defaultbeansdefault-autowire來決定。property節(jié)點:ref、valuenull都可以作為該節(jié)點的子節(jié)點,propertyname屬<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTDDTD文件,在下面的章節(jié)中,將會講解如何將絕對路徑url。在使用d4j之前,我們需要下載do4j的包,下載完包之后,可以將包放到項目的環(huán)境變量中。mj的包可以從rere中下到,下載的地址為:hporereerecdom4iles/,本4j161。XMLXML,并將讀取到的Document對象緩存。建立DocumentHolder接口。}為該接口新建一個實現(xiàn)類XmlDocumentHolder。privateMap<String,Document>docs=newHashMap<String,Document>();publicDocumentgetDocument(StringfilePath){Documentdoc=this.docs.get(filePath);if(doc==null){}return}{trySAXReaderreader=new//使用自己的EntityResolverFilexmlFile=newFile(filePath);//讀取文件并返回Document對象returndoc;}catch(Exception{thrownew}}}MapDocument對象,如果取到就返回,如果取不到該對象,就通過IoCEntityResolver的代碼如下。publicInputSourceresolveEntity(StringpublicId,StringsystemId)throwsSAXException,IOException{if{InputStreamstream=IoCEntityResolver.class.returnnewInputSource(stream);}elsereturn}}}<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTDXMLIoCEntityResolverresolveEntity方法中的systemIdXMLDTD文件,但事實上是從本地的編譯路徑publicpublicclassXmlHolderTestextendsTestCaseprotectedvoidsetUp()throws{holder=new}protectedvoidtearDown()throws{holder=}publicvoidtestGetDoc()StringfilePath=Elementroot=doc.getRootElement();Documentdoc2=holder.getDocument(filePath);}}XmlDocumentHoder對象,測試后將其銷testJunit4中,提供了@Test的注工具,可以使用main方法進(jìn)行測試,并查看結(jié)果。<beanid="test"class="JunitXmlHolderTest的結(jié)果如下:Junit可以直接寫斷言,在這里XMLIoCDocument得到所有的Element對象,也就是配置文件中的每一個bean。//加入一份doc的所有Element//返回全部的Element}DTD規(guī)范,因此,不用去擔(dān)心XML不符合我們的要求。//Map來保存Map的keybean元素的idvaluebeanElementprivateMap<String,Element>elements=newHashMap<String,Element>();publicvoidaddElements(Documentdoc){//讀取根節(jié)點beans,再得到所有的bean節(jié)點for(Elemente:eles){//bean的idStringid=}}{return}{return}}XmlDocumentHolder一樣,ElementHoderImplMapElement,當(dāng)調(diào)addElementDocumentElement元素(bean節(jié)點)都放到MapXMLIoC容器中,beanid必須是唯一的,否則的話,先讀取的Element對象,會被后讀取的名字相同的Element覆蓋。<beanid="test3"class="<beanid="test4"class="StringfilePath="test/resources/ElementLoader.xml";Documentdoc=holder.getDocument(filePath);Elemente=elementLoader.getElement("test1");} 可以看到結(jié)果為4。ElementElement進(jìn)行解析,得到相關(guān)的信息。例如,我們需要判斷得到這些信息的。新建ElementReader接口。獲得一個//beanconstructor-arg的值(包括value和ref)List<DataElement>getConstructorValue(Elementelement);//bean元素下所有property元素的值(包括value和ref)}應(yīng)的Element集合。值和value的值。publicpublicinterfaceAutowireStringgetValue();}Autowirebeanautowireautowire的byNameAutowireByNameAutowire。{privateString{this.value=}{return}}NoAutowireByNameAutowire一樣,這兩個對象只是用于判斷值的類ValueElement,前者表示一個ref的節(jié)點,后者表示一個value節(jié)點,DataElement代碼如下。StringgetType();}publicclasspublicclassRefElementimplements{privateObject{this.value=}{return}{return}}ValueElement的實現(xiàn)與RefElement一樣,在這里不寫出代碼。在接口中,另外還有g(shù)etPropertyValuePropertyElement來表示值的類型。PropertyElement里面封裝點下面除了可以有這兩個節(jié)點之外,property節(jié)點還有一個name的屬性,因此再另外封裝成一個publicpublicclassPropertyElementprivateString{=name;}}publicpublicbooleanisLazy(Elementelement)Stringlazy=getAttribute(element,"lazy-init");Elementparent=element.getParent();BooleanparentLazy=newBoolean(getAttribute(parent,"default-lazy-init"));if(parentLazy){if("false".equals(lazy))returnfalse;returntrue;}elseif("true".equals(lazy))returntrue;returnfalse;}}List<Element>children=element.elements();List<Element>result=newArrayList<Element>();for(Elemente:children){}}return}即可,并不需要作其他處理。getPropertyElementsgetPropertyElements方法返回的是property節(jié)點集合。ElementReaderImplgetAttribute{Stringvalue=element.attributeValue(name);returnvalue;}Booleansingleton=newBoolean(getAttribute(element,"singleton"));returnsingleton;}DTD文件中定義singleton屬性值只能是truefalse,因此在這里不需要作處理。getAutowire方法的實現(xiàn)與14.4.4中的isLazy方法一致,只是getAutowire方法返回的是一個nobyNamebyType等狀態(tài)時,我們可以加多一個Autowire的實現(xiàn)類。以下是getAutowire的實現(xiàn)。StringparentValue=this.getAttribute(element.getParent(),"default-autowire");if("no".equals(parentValue)){if("byName".equals(value))returnnewByNameAutowire(value);returnnewNoAutowire(value);//根節(jié)點if("no".equals(value))returnnewNoAutowire(value);returnnewByNameAutowire(value);}returnnew getConstructorValueDataElement的集合,實現(xiàn)相對麻煩,如果再對value節(jié)點的值進(jìn)行轉(zhuǎn)換。以下是getConstructorValue的實現(xiàn)。List<Element>cons=getConstructorElements(element);List<DataElement>result=newArrayList<DataElement>();for(Elemente:cons)//constructor-arg下的ref元素或者value元素(只有一個)List<Element>els=e.elements();DataElementdataElement=getDataElement(els.get(0));}return}{Stringname=dataElement.getName();if("value".equals(name)){Stringdata=dataElement.getText();}elseif("ref".equals(name))}return}{if(isType(className,"Integer")){returnInteger.parseInt(data);elsereturn}}{if(className.indexOf(type)!=-1)returntrue;returnfalse;}//調(diào)用本類中的getPropertyElements取得所有的property節(jié)點List<Element>properties=getPropertyElements(element);List<PropertyElementresultnewArrayList<PropertyElement>();for(Elemente:properties){//將數(shù)據(jù)值和property元素的name屬性封裝成PropertyElement對象PropertyElementpenewPropertyElement(propertyNameAttdataElement);}return}getPropertyValue方法與getConstructorValue方法的實現(xiàn)類似,getConstructorValue是得到constructor-argvalueref節(jié)點值,getPropertyValuevalue節(jié)點refgetPropertyValuePropertyElement對象集合,PropertyElement對象中包含了DataElement和一個名字,這是由于property節(jié)點中還需要有一個name屬性。beanbean的constructor-arg節(jié)點,去創(chuàng)建一個bean的實例。我們的配置文件中,bean節(jié)點下面可以出現(xiàn)多個constructor-argbeanbean的時候,就可以根據(jù)構(gòu)造注入,顧名思義,就是通過構(gòu)造器將對應(yīng)的值(bean)XML中只需要beanconstructor-arg,并分配相應(yīng)的值即可,IoC容器得到這些值后,就通過調(diào)用bean對應(yīng)的Class的構(gòu)造器創(chuàng)建該bean實例。bean的實例。分兩種情況,一種是沒有構(gòu)造參數(shù)的情況,另外一種是配置了參//使用無參的構(gòu)造器創(chuàng)建bean實例,}行時異常。我們先實現(xiàn)第一個無參數(shù)構(gòu)造器創(chuàng)建bean的方法,該方法實現(xiàn)比較簡單。{tryClassclazz=returnthrownewBeanCreateException("classnotfound"+}catch(Exceptione)thrownew}}ClassNotFoundException,我們將這個異常進(jìn)行封裝,封成我們的自定義異常。那么外界beanclass屬性值,傳遞給該方法就可以返回對應(yīng)的實例,但是前提是需要判斷該bean是否有構(gòu)造參數(shù)。13.5.2中,我們編寫調(diào)用類的無參數(shù)構(gòu)造器創(chuàng)建實例,如果在XML配置中,bean節(jié)點下面有ListcreateBeanUseDefineConstruce的實publicpublicObjectcreateBeanUseDefineConstruce(StringclassName,List<Object>args){try{Classclazz=Constructorconstructor=findConstructor(clazz,argsClass);returnconstructor.newInstance(args.toArray());{thrownewBeanCreateException("classnotfound"+{thrownewBeanCreateException("nosuchconstructor"+}catch(Exception{thrownew}}//獲得構(gòu)造器,如果沒有找到,NoSuchMethodException,返回nullprivateConstructorgetConstructor(Classclazz,Class[]argsClass){tryConstructorconstructor=clazz.getConstructor(argsClass);returnconstructor;{return}}privateConstructorfindConstructor(Classclazz,Class[]argsClass)throwsNoSuchMethodException{Constructorconstructor=getConstructor(clazz,argsClass);if(constructor==null){Constructor[]constructors=clazz.getConstructors();for(Constructorc:constructors){if(constructorArgsCLass.length==argsClass.length){if(isSameArgs(argsClass,constructorArgsCLass)){return}}}}elsereturn}thrownewNoSuchMethodException("couldnotfindany}{for(inti=0;i<argsClass.length;i++){try{//循環(huán)到最后一個都沒有出錯,if(i==(argsClass.length-{return}}catch(Exceptione)//有一個參數(shù)類型不符合,}}return}}{if(objinstanceofInteger){returnInteger.TYPE;}elseif(objinstanceof{return}elseif(objinstanceof{return}elseif(objinstanceof{return}elseif(objinstanceof{return}elseif(objinstanceof{return}elseif(objinstanceof{return}elseif(objinstanceof{return}return}{List<Class>result=newArrayList<Class>();for(Objectarg:args){}Class[]a=newClass[result.size()];returnresult.toArray(a);}中一個實現(xiàn),那么這樣就會拋出NoSuchMethodException,我們這里直接返回null。isSameArgs方法:判斷參數(shù)中第一個類型數(shù)組與第二個類型數(shù)組里面對應(yīng)的類型是否相同,數(shù)組中的類型,如果全部都是類型相同,那么就返回true。findConstructorClassgetConstructor方getConstructor方法將返回調(diào)用isSameArgs方法判斷,如果可以找到對應(yīng)的構(gòu)造器,就直接返回,否則拋出createBeanUseDefineConstrucefindConstructor方法得到相應(yīng)的構(gòu)造器,得到構(gòu)造器后,通過Constructor對象的newInstance方法創(chuàng)建實例。了多態(tài)的特性,那么將不能直接找到該構(gòu)造器,還要經(jīng)過Class的asSubclass方法進(jìn)行類型轉(zhuǎn)換,如果//無參數(shù)構(gòu)造器創(chuàng)建實例//無參數(shù)構(gòu)造器創(chuàng)建實例BeanCreatorObject1Java對象name和valueBeanCreatorObject1obj=(BeanCreatorObject1)StringclassName=List<Object>StringclassName=List<Object>args=newArrayList<Object>();BeanCreatorObject2obj=(BeanCreatorObject2)}publicpublicObjectsetProperties(Objectobj,Map<String,Object>{Classclazz=obj.getClass();try{for(Stringkey:properties.keySet())ClassargClass=getClass(properties.get(key));MethodsetterMethod=getSetterMethod(clazz,setterName,argClass);setterMethod.invoke(obj,properties.get(key));}returnthrownewPropertyException("settermethodnotfound"+thrownewPropertyException("wrongargument"+}catch(Exceptione)thrownew}}//Object的{if(objinstanceofInteger){returnInteger.TYPE;return}privateMethodgetSetterMethod(ClassobjClass,StringmethodName,ClassargClass)throwsNoSuchMethodException{//使用原類型獲得方法,如果沒有找到該方法,,if(argClassMethod==null)List<Method>methods=getMethods(objClass,methodName);Methodmethod=findMethod(argClass,methods);if(method==null)thrownew}return}elsereturn}}{List<Method>result=newArrayList<Method>();for(Methodm:objClass.getMethods()){//得到方法的所有參數(shù),如果只有一個參數(shù),Class[]c=m.getParameterTypes();if(c.length==1){}}}return},{for(Methodm:methods)if(isMethodArgs(m,argClass)){return}}return},privatebooleanisMethodArgs(Methodm,ClassargClass)Class[]c=,if(c.length=={try,return{return}}return}//將參數(shù)s{StringfirstWord=s.substring(0,StringupperCaseWord=}{return"set"+},privateMethodgetMethod(ClassobjClass,StringmethodName,Class{tryMethodmethod=objClass.getMethod(methodName,argClass);returnmethod;{return}}upperCaseFirstWord方法:將參數(shù)中的字符串的首字母變?yōu)榇髮懀?dāng)我們得到一個屬性名為age配置屬性(<propertyname=”age”>)agesetter方法(setAge),因此需要將age的首字母變成大寫。ClassMethodClassMethod的參數(shù)類型是一個接口,而具體的參數(shù)值是該接口的實現(xiàn)類,我們就需要使用Class中的getMethods方法:給一個類型和方法名,到該類型中尋找方法名與參數(shù)的方法名一致的方法,findMethodargClass一致,判斷類型是否一致使用以上的isMethodArgs進(jìn)行判斷。如果類型一致,則馬上返回。getMethod方法:直接通過類名、方法名和方法參數(shù)類型查找方法,如果查找不到,則直接返null。getSetterMethodsetter方法。先調(diào)用getMethod方法尋找方法,如果該方法的參數(shù)類型是接口,而參數(shù)值類型是該接口的實現(xiàn)類,那么將和構(gòu)造注入一樣,找不到對應(yīng)的方法。因此在getSetterMethod方法中,再調(diào)用findMethod方法進(jìn)行查找。先得到對象的類型,再得到所有遍歷所有在bean節(jié)點下配置的property節(jié)點及其對應(yīng)的值(setProperties方法的第二個參數(shù)setter方法的字符串名字,再得到方法參數(shù)行了對象的setter方法了。PropertyHandlerObject1obj=newMap<String,Map<String,Object>properties=newHashMap<String,Object>();properties.put("name","yangenxiong");//School是普通的Java對象Schoolschool=newSchool();",PropertyHandlerObject1newObj=(PropertyHandlerObject1)handler.setProperties(obj,properties);最后兩行的打印,PropertyHandlerObject1School對象和我們所創(chuàng)建(new)School試代碼中,PropertyHandlerObject1需要為name、ageschoolsetter方法,方法名分別是setName、setAge和setSchool。到,則調(diào)用setter方法進(jìn)行設(shè)值,沒有找到就忽略,這樣就可以實現(xiàn)自動裝配,不再需要進(jìn)行任何的property配置。這樣做的好處在于,可以簡化配置文件,但是同時將程序的耦合降到代碼程度,我們提供配置文件,是為了讓程序的耦合只在配置文件中體現(xiàn),是否進(jìn)行autowire各有利弊。始編寫IoC容器的主體代碼,我們本小節(jié)所編寫的代碼,將在14.7中詳細(xì)描述用處。////setter方法mapkeysetter方法名不要setMap<String,Method>getSetterMethodsMap(Objectobj);@paramargBean參數(shù)的@parammethodbeanMa接口中的executeMethod方法執(zhí)行setter方法。publicpublicvoidexecuteMethod(Objectobject,ObjectargBean,Method{tryClass[]parameterTypes=if(parameterTypes.length==1){{method.invoke(object,}}}catch(Exceptione)thrownewBeanCreateException("autowireexception"+}}publicMap<String,Method>getSetterMethodsMap(Object{List<Method>methods=getSetterMethodsList(obj);Map<String,Method>result=newHashMap<String,Method>();for(Methodm:methods){StringpropertyName=getMethodNameWithOutSet(m.getName());result.put(propertyName,m);}return}{Classclazz=Method[]methods=clazz.getMethods();List<Method>result=newArrayList<Method>();for(Methodm:methods){if{}}return}//將setter方法還原,如setName作為參數(shù),最后返回nameprivateStringgetMethodNameWithOutSet(StringmethodName)StringpropertyName=methodName.replaceFirst("set","");StringfirstWord=propertyName.substring(0,1);StringlowerFirstWord=}}isMethodArgs方法:以上代碼的黑體部分為isMethodArgs方法,重用了14.6.1中的PropertyHandlerObject1obj=newPropertyHandlerObject1();Map<String,Method>result=handler.getSetterMethodsMap(obj);publicvoidorg.crazyit.ioc.context.object.PropertyHandlerObject1.setAge(int)publicvoidorg.crazyit.ioc.context.object.PropertyHandlerObject1.setAge(int)publicvoidPropertyHandlerObject1PropertyHandlerObject1obj=newPropertyHandlerObject1();Schoolschool=newSchool();Methodm=obj.getClass().getMethod("setSchool",School.class);handler.executeMethod(obj,school,m);IoCbeanPropertyHandler找這些bean的代碼,只是更關(guān)注于值設(shè)置。14.5節(jié)中的構(gòu)造注入,我們已經(jīng)大致上實現(xiàn)了設(shè)值注入和構(gòu)造注入,在下一節(jié)中,我們編寫IoC容器的主體代碼。14.5bean14.6的設(shè)值注入代碼,為對象設(shè)置相我們需要創(chuàng)建一個 根據(jù)id@paramidbean節(jié)點的IoC容器中是否包含id@param@returntrue判斷一個bean@paramidbean節(jié)點的@return如果該bean是單態(tài)的,返回獲得beanbean@paramidbean節(jié)點的@return找到的bean}getBeanbeanidIoCbean的實例,如果查找不到,則嘗試進(jìn)行創(chuàng)建該bean的實例。AbstractApplicationContext中,我們暫時提供空實現(xiàn),現(xiàn)在新建一個方法,用于處理讀取的XML文件。protectedElementLoaderelementLoader=newprotectedDocumentHolderdocumentHolder=newprotectedMap<String,Object>beans=newHashMap<String,protectedPropertyHandlerpropertyHandler=newprotectedBeanCreatorbeanCreator=newprotectedElementReaderelementReader=newURLclassPathUrl=StringclassPath=.URLDecoder.decode(classPathUrl.getPath(),"utf-8");for(Stringpath:xmlPaths){Documentdoc=documentHolder.getDocument(classPath+path);}}}Element的接口、創(chuàng)建類實例的接口和類屬性的處理接口,我們在前面幾節(jié)中已經(jīng)對這些接口進(jìn)行14.4DocumentHolderElementLoader接口,DocumentDocumentElement對象進(jìn)行緩存,這里的ElementbeanDTDbeans節(jié)點下bean0DocumentElement對象,那么實現(xiàn)containsBean方法和isSingleton方法就十分簡單,以下為兩個方法的實現(xiàn)。publicpublicbooleancontainsBean(Stringid)//ElementLoader對象根據(jù)idElementElemente=elementLoader.getElement(id);return(e==null)?false:true;}Elemente=elementLoader.getElement(id);return}接口主要用于處理Element對象的解析,具體的使用在本章的14.4.3中的詳細(xì)說明。性中進(jìn)行緩存,因此我們需要從所有的Element中查找。bean實例,如果查找不到,那么就進(jìn)行創(chuàng)建。創(chuàng)建的順序是先根據(jù)構(gòu)造器來創(chuàng)建實例,再對該bean進(jìn)行設(shè)值。publicpublicObjectgetBean(String{Objectbean=if(bean==null)bean=handleSingleton(id);}return}//bean,如果是單態(tài)的,則加到map中,非單態(tài),{Objectbean=//單態(tài)的話map}return}//bean實例并設(shè)置屬性如果找不到該beanElement對象,protectedObjectcreateBean(Stringid){if(e==null)thrownewBeanCreateException("elementnotfound"+id);Objectresult=instance(e);System.out.println("創(chuàng)建bean:"+id);returnresult;}protectedprotectedObjectinstance(Elemente)if(constructorElements.size()==0){return}else//constructor-arg子元素使用有參數(shù)構(gòu)造器,List<Object>args=}}protectedList<Object>getConstructArgs(Element{List<DataElement>datas=elementReader.getConstructorValue(e);List<Object>result=newfor(DataElementd:datas)if(dinstanceof{d=(ValueElement)d;}elseif(dinstanceofRefElement)//如果是引用元素,則直接調(diào)getBean去獲取(獲取不到則創(chuàng)建)d=(RefElement)d;StringrefId=(String)d.getValue();}}returngetConstructArgs方法:該方法得到bean節(jié)點下面所有constructor-arg節(jié)點的值,constructor-argrefbeanvalue節(jié)點的值,通過調(diào)用ElementReader接口的getConstructorValue方法取得所有的值對象集合,getConstructorValue方法已經(jīng)幫我們將這些值封裝成DataElement對象,再判斷DataElement的類型,如果是再次調(diào)用getBean方法得到容器中的bean實例,實際上這里是遞歸調(diào)用。具體getConstructorValue方法的實現(xiàn)與使用,請看14.4.8中該方法的詳細(xì)描述。instanceElementbean的實例,這里使用了構(gòu)造器createBeanUseDefaultConstructconstructor-arg節(jié)點參數(shù)不為0,就調(diào)用本類中的getConstructArgs方法獲得參數(shù),再調(diào)用BeanCreator的使用,請參看本章14.5節(jié)。Elementinstancebean的實例,再被設(shè)置為單態(tài)的,如果被設(shè)置為單態(tài)的(beansingletontrue),那么就將對象一種是通過名字自動裝配,另外一種是不自動裝配,因此就需要進(jìn)行判斷。以上是對AbstractApplicationContext中的createBean方法的補(bǔ)充。////bean實例并設(shè)置屬性如果找不到該beanElement對象,protectedObjectcreateBean(Stringid){if(e==null)thrownewBeanCreateException("elementnotfound"+id);Objectresult=instance(e);,Autowireautowire=elementReader.getAutowire(e);if(autowireinstanceofByNameAutowire){}elseif(autowireinstanceofNoAutowire),}return}自動裝配一個對象得到該beansetter方法,再從容器中查找對應(yīng)的@paramMap<String,Method>methods=for(Strings:methods.keySet())Elemente=//沒有對應(yīng)的元素配置if(e==null)Objectbean=////獲得MethodMethodmethod=}}protectedvoidsetterInject(Objectobj,Elemente)//property節(jié)點下面的值refbean屬性和value//調(diào)用本類的getPropertyArgs方法裝參數(shù)集合重新封裝成Map}),{Map<String,Object>result=newHashMap<String,Object>();for(PropertyElementp:properties){if(deinstanceofRefElement){//bean的實例,再設(shè)置入map}elseif(deinstanceofValueElement)}}return}對應(yīng)的bean。PropertyHandler接口的實現(xiàn)與使用,請看本章的14.6.1節(jié)。后,再調(diào)用setter方法將bean設(shè)值到這個實例中。該方法中使用了PropertyHandler的getSetterMethodsMapexecuteMethod14.6.2節(jié)(byName節(jié)點的ref節(jié)點類似(AbstractApplicationContext類中的getConstructArgs方法。getBeangetBeanIgnoreCreate的接口方法沒有實現(xiàn)了,該方法十{return}AbstractApplicationContext是一個抽象類,并不可以實例化,因此我們?yōu)樗砑右粋€子類{publicXmlApplicationContext(String[]xmlPaths)}}XmlApplicationContextxml文件的路徑,得到參數(shù)后,再調(diào)個創(chuàng)建bean的方法,當(dāng)加載完配置文件后,就馬上啟動IoC容器創(chuàng)建tectedvoidcreateBeans()Collection<Element>elements=elementLoader.getElements();for(Elemente:elements){booleanlazy=//如果不是延遲加載if(!lazy)Objectbean=this.getBean(id);if(bean==null){//bean如果是單態(tài)的,加到緩存中,}}}}AbstractApplicationContexthandleSingleton方法創(chuàng)建}XMLgetBeanbean。{publicXmlBeanFactory(String[]xmlPaths)//只初始化文檔,不創(chuàng)建任何bean}}AbstractApplicationContextIoC<bean<beanid="test1"下面的代碼使用XmlApplicationContext來創(chuàng)建IoC容器:ApplicationContextApplicationContextctx=new(new//拿到test1,//拿到test1,getBeanbeanid和過調(diào)用bean的無參數(shù)構(gòu)造器來創(chuàng)建實例。下面我們測試beansingleton屬性(是否單態(tài)。<beanid="test1"http://test1//test1是單態(tài)XmlApplicationContextObject1obj3=(XmlApplicationContextObject1)ctx.getBean("test3");XmlApplicationContextObject1obj4=(XmlApplicationContextObject1)ctx.getBean("test3");<beanid="test1"<beanid="test2"<value<value<ref,//打印test2的name//打印test2的age//打印test1的bean//打印test2object1對象,XmlApplicationContextObject2中有一個屬性叫object1XmlApplicationContextObject1類型。<bean以上的配置中,object1不自動裝配,test4使用自動裝配,XmlApplicationContextObject1對象里面沒有任何的屬性,XmlApplicationContextObject3的屬性如下:{privateStringname;privateintage;}以上的測試代碼中,先從容器中得到一個XmlApplicationContextObject3對象,再通過該對象的getObject1方法得到XmlApplicationContextObject1對象,再從容器中通過getBean方法得到XmlApplicationContextObject1hashCode器中的bean設(shè)置到實例里面。<beanid="test6"<property<value<property<value<property<property<ref注意:我們在本節(jié)中所使用的XmlApplicationContextObject1、XmlApplicationContextObject2XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1obj2=(XmlApplicationContextObject1)ctx.getBean("object1");hashCodegetBeanhashCode一致。以上的配置只有一個bean,該bean是需要延遲加載的,我們可以調(diào)用ApplicationContext的//test5//test5是延遲加載的getBean方法beanObjectobj=ctx.getBeanIgnoreCreate("test5");obj=<beanid="test1"<beanid="test1"beanXmlBeanFactorybean不會ApplicationContextApplicationContextctx=newXmlBeanFactory(new們編寫的這個IoC所帶來的好處。beanIoC容器幫我們?nèi)?chuàng)建它們的實例和對它們進(jìn)行管理,我newIoC容器帶我們帶來的好處。在閱讀本節(jié)前,可以先去了解第9章圖書進(jìn)存銷系統(tǒng)的分層結(jié)構(gòu)。JPanelJFrame對14.1中我們可以看到,圖書進(jìn)存銷系統(tǒng)中,各個視圖對象里面都有一個或者多個業(yè)務(wù)層接口對象做成bean,并注入到Mai

溫馨提示

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

評論

0/150

提交評論