版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
IoCnewnew這個(gè)類,就可以得到該實(shí)例呢?IoC的概念很好的幫助我們解決了這個(gè)問(wèn)題,當(dāng)我們需要在一個(gè)類中使用另外的類時(shí),可以通過(guò)一些配置來(lái)得到該類的實(shí)現(xiàn)。IoCInversionofControl簡(jiǎn)稱,又稱控制反轉(zhuǎn),一搞清楚了控制反轉(zhuǎn)的概念后,我們?cè)賮?lái)了解什么叫依賴注入。依賴注入(DependencyInjection)那么可以在IoC容器中向該類注入需要被調(diào)用的實(shí)例。而不需要關(guān)注各個(gè)組件的依賴的關(guān)系。常用的IoCSpringIoC容器、webworkIoC容器、google-guice,apache的HiveMind等。一個(gè)整合的例子,來(lái)說(shuō)明IoC容器給我們帶來(lái)什么樣的好處。機(jī)制可以讓我們動(dòng)態(tài)的得到某個(gè)類型的屬性、構(gòu)造器和方法。Java的反射機(jī)制可以在運(yùn)行時(shí)構(gòu)造某一這些實(shí)例設(shè)置相應(yīng)的屬性,因此我們需要使用Java的反射機(jī)制。們的IoC容器的配置文件,因此使用dom4j就非常的合適。JunitJava程序員編寫單元測(cè)試。在本章中,我們每編寫一個(gè)功能點(diǎn),就如果站在XP(極限編程)的角度來(lái)講,編寫測(cè)試可以讓我們的代碼更加健壯,更不懼任何的變更,對(duì)果,我們當(dāng)前所使用的是Junit4。(beanbean是否為單態(tài),是否需要延遲加載定。確定了配置文件的內(nèi)容后,我們開(kāi)始著手編寫DTD文件。聲明…個(gè)bean…與類型,這些我們的IoC容器得到這些配置后,就可以幫我們創(chuàng)建這些類的實(shí)例。具體的配置如下:以上的bean配置表示我們?cè)贗oC容器中創(chuàng)建了一個(gè)myDate的bean,該bean聲明單態(tài)的beanbean的時(shí)候,就重新創(chuàng)建一個(gè)。我們?yōu)閎ean的配置添加一個(gè)singleton屬性,用來(lái)聲明bean是否為單態(tài)。IoCbean,我們可以為配置文件提供一個(gè)屬性,讓容器知道我們?cè)谌萜鞒跏蓟臅r(shí)候,是否需要?jiǎng)?chuàng)建。我們?yōu)閎ean提供一個(gè)lazy-init的屬性: myDatebean節(jié)點(diǎn)加了這個(gè)屬性后,beans節(jié)點(diǎn)也default-lazy-initbeanbeanlazy-initlazy-init屬性不顯式指定的話,可以使用false作為默認(rèn)值。<property<ref<property<ref<beanid="school"studentbeanschoolbean,這樣,school和屬性,propertyref子節(jié)點(diǎn),refbean。除了注入另外定義的bean外,還可以向bean中注入一些普通的屬性:<property<value<ref<ref<valuestudentbeanStudent類提供一個(gè)構(gòu)Student<valueStudentbean<beanid="school"<beanid="school"studentautowirebyNamebean的名稱自動(dòng)注入到studentStudentsetSchoolsetterSchoold對(duì)象,那么容器SchoolbeanStudentbeansdefault,那么就可以進(jìn)行自動(dòng)裝配。<beans<beans<beanid="school"示不需要自動(dòng)裝配。beanautowire屬性默認(rèn)值為default。的約束文件(DTD。簡(jiǎn)單的說(shuō),DTD就是一種對(duì)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é)點(diǎn):beansbean節(jié)點(diǎn),beanidclass屬性,可以值,autowire屬性的默認(rèn)值是defaultbeansdefault-autowire來(lái)決定。property節(jié)點(diǎn):ref、valuenull都可以作為該節(jié)點(diǎn)的子節(jié)點(diǎn),propertyname屬<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTDDTD文件,在下面的章節(jié)中,將會(huì)講解如何將絕對(duì)路徑url。在使用d4j之前,我們需要下載do4j的包,下載完包之后,可以將包放到項(xiàng)目的環(huán)境變量中。mj的包可以從rere中下到,下載的地址為:hporereerecdom4iles/,本4j161。XMLXML,并將讀取到的Document對(duì)象緩存。建立DocumentHolder接口。}為該接口新建一個(gè)實(shí)現(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對(duì)象returndoc;}catch(Exception{thrownew}}}MapDocument對(duì)象,如果取到就返回,如果取不到該對(duì)象,就通過(guò)IoCEntityResolver的代碼如下。publicInputSourceresolveEntity(StringpublicId,StringsystemId)throwsSAXException,IOException{if{InputStreamstream=IoCEntityResolver.class.returnnewInputSource(stream);}elsereturn}}}<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTDXMLIoCEntityResolverresolveEntity方法中的systemIdXMLDTD文件,但事實(shí)上是從本地的編譯路徑publicpublicclassXmlHolderTestextendsTestCaseprotectedvoidsetUp()throws{holder=new}protectedvoidtearDown()throws{holder=}publicvoidtestGetDoc()StringfilePath=Elementroot=doc.getRootElement();Documentdoc2=holder.getDocument(filePath);}}XmlDocumentHoder對(duì)象,測(cè)試后將其銷testJunit4中,提供了@Test的注工具,可以使用main方法進(jìn)行測(cè)試,并查看結(jié)果。<beanid="test"class="JunitXmlHolderTest的結(jié)果如下:Junit可以直接寫斷言,在這里XMLIoCDocument得到所有的Element對(duì)象,也就是配置文件中的每一個(gè)bean。//加入一份doc的所有Element//返回全部的Element}DTD規(guī)范,因此,不用去擔(dān)心XML不符合我們的要求。//Map來(lái)保存Map的keybean元素的idvaluebeanElementprivateMap<String,Element>elements=newHashMap<String,Element>();publicvoidaddElements(Documentdoc){//讀取根節(jié)點(diǎn)beans,再得到所有的bean節(jié)點(diǎn)for(Elemente:eles){//bean的idStringid=}}{return}{return}}XmlDocumentHolder一樣,ElementHoderImplMapElement,當(dāng)調(diào)addElementDocumentElement元素(bean節(jié)點(diǎn))都放到MapXMLIoC容器中,beanid必須是唯一的,否則的話,先讀取的Element對(duì)象,會(huì)被后讀取的名字相同的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接口。獲得一個(gè)//beanconstructor-arg的值(包括value和ref)List<DataElement>getConstructorValue(Elementelement);//bean元素下所有property元素的值(包括value和ref)}應(yīng)的Element集合。值和value的值。publicpublicinterfaceAutowireStringgetValue();}Autowirebeanautowireautowire的byNameAutowireByNameAutowire。{privateString{this.value=}{return}}NoAutowireByNameAutowire一樣,這兩個(gè)對(duì)象只是用于判斷值的類ValueElement,前者表示一個(gè)ref的節(jié)點(diǎn),后者表示一個(gè)value節(jié)點(diǎn),DataElement代碼如下。StringgetType();}publicclasspublicclassRefElementimplements{privateObject{this.value=}{return}{return}}ValueElement的實(shí)現(xiàn)與RefElement一樣,在這里不寫出代碼。在接口中,另外還有g(shù)etPropertyValuePropertyElement來(lái)表示值的類型。PropertyElement里面封裝點(diǎn)下面除了可以有這兩個(gè)節(jié)點(diǎn)之外,property節(jié)點(diǎn)還有一個(gè)name的屬性,因此再另外封裝成一個(gè)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é)點(diǎn)集合。ElementReaderImplgetAttribute{Stringvalue=element.attributeValue(name);returnvalue;}Booleansingleton=newBoolean(getAttribute(element,"singleton"));returnsingleton;}DTD文件中定義singleton屬性值只能是truefalse,因此在這里不需要作處理。getAutowire方法的實(shí)現(xiàn)與14.4.4中的isLazy方法一致,只是getAutowire方法返回的是一個(gè)nobyNamebyType等狀態(tài)時(shí),我們可以加多一個(gè)Autowire的實(shí)現(xiàn)類。以下是getAutowire的實(shí)現(xiàn)。StringparentValue=this.getAttribute(element.getParent(),"default-autowire");if("no".equals(parentValue)){if("byName".equals(value))returnnewByNameAutowire(value);returnnewNoAutowire(value);//根節(jié)點(diǎn)if("no".equals(value))returnnewNoAutowire(value);returnnewByNameAutowire(value);}returnnew getConstructorValueDataElement的集合,實(shí)現(xiàn)相對(duì)麻煩,如果再對(duì)value節(jié)點(diǎn)的值進(jìn)行轉(zhuǎn)換。以下是getConstructorValue的實(shí)現(xiàn)。List<Element>cons=getConstructorElements(element);List<DataElement>result=newArrayList<DataElement>();for(Elemente:cons)//constructor-arg下的ref元素或者value元素(只有一個(gè))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é)點(diǎn)List<Element>properties=getPropertyElements(element);List<PropertyElementresultnewArrayList<PropertyElement>();for(Elemente:properties){//將數(shù)據(jù)值和property元素的name屬性封裝成PropertyElement對(duì)象PropertyElementpenewPropertyElement(propertyNameAttdataElement);}return}getPropertyValue方法與getConstructorValue方法的實(shí)現(xiàn)類似,getConstructorValue是得到constructor-argvalueref節(jié)點(diǎn)值,getPropertyValuevalue節(jié)點(diǎn)refgetPropertyValuePropertyElement對(duì)象集合,PropertyElement對(duì)象中包含了DataElement和一個(gè)名字,這是由于property節(jié)點(diǎn)中還需要有一個(gè)name屬性。beanbean的constructor-arg節(jié)點(diǎn),去創(chuàng)建一個(gè)bean的實(shí)例。我們的配置文件中,bean節(jié)點(diǎn)下面可以出現(xiàn)多個(gè)constructor-argbeanbean的時(shí)候,就可以根據(jù)構(gòu)造注入,顧名思義,就是通過(guò)構(gòu)造器將對(duì)應(yīng)的值(bean)XML中只需要beanconstructor-arg,并分配相應(yīng)的值即可,IoC容器得到這些值后,就通過(guò)調(diào)用bean對(duì)應(yīng)的Class的構(gòu)造器創(chuàng)建該bean實(shí)例。bean的實(shí)例。分兩種情況,一種是沒(méi)有構(gòu)造參數(shù)的情況,另外一種是配置了參//使用無(wú)參的構(gòu)造器創(chuàng)建bean實(shí)例,}行時(shí)異常。我們先實(shí)現(xiàn)第一個(gè)無(wú)參數(shù)構(gòu)造器創(chuàng)建bean的方法,該方法實(shí)現(xiàn)比較簡(jiǎn)單。{tryClassclazz=returnthrownewBeanCreateException("classnotfound"+}catch(Exceptione)thrownew}}ClassNotFoundException,我們將這個(gè)異常進(jìn)行封裝,封成我們的自定義異常。那么外界beanclass屬性值,傳遞給該方法就可以返回對(duì)應(yīng)的實(shí)例,但是前提是需要判斷該bean是否有構(gòu)造參數(shù)。13.5.2中,我們編寫調(diào)用類的無(wú)參數(shù)構(gòu)造器創(chuàng)建實(shí)例,如果在XML配置中,bean節(jié)點(diǎn)下面有ListcreateBeanUseDefineConstruce的實(shí)publicpublicObjectcreateBeanUseDefineConstruce(StringclassName,List<Object>args){try{Classclazz=Constructorconstructor=findConstructor(clazz,argsClass);returnconstructor.newInstance(args.toArray());{thrownewBeanCreateException("classnotfound"+{thrownewBeanCreateException("nosuchconstructor"+}catch(Exception{thrownew}}//獲得構(gòu)造器,如果沒(méi)有找到,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)到最后一個(gè)都沒(méi)有出錯(cuò),if(i==(argsClass.length-{return}}catch(Exceptione)//有一個(gè)參數(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);}中一個(gè)實(shí)現(xiàn),那么這樣就會(huì)拋出NoSuchMethodException,我們這里直接返回null。isSameArgs方法:判斷參數(shù)中第一個(gè)類型數(shù)組與第二個(gè)類型數(shù)組里面對(duì)應(yīng)的類型是否相同,數(shù)組中的類型,如果全部都是類型相同,那么就返回true。findConstructorClassgetConstructor方getConstructor方法將返回調(diào)用isSameArgs方法判斷,如果可以找到對(duì)應(yīng)的構(gòu)造器,就直接返回,否則拋出createBeanUseDefineConstrucefindConstructor方法得到相應(yīng)的構(gòu)造器,得到構(gòu)造器后,通過(guò)Constructor對(duì)象的newInstance方法創(chuàng)建實(shí)例。了多態(tài)的特性,那么將不能直接找到該構(gòu)造器,還要經(jīng)過(guò)Class的asSubclass方法進(jìn)行類型轉(zhuǎn)換,如果//無(wú)參數(shù)構(gòu)造器創(chuàng)建實(shí)例//無(wú)參數(shù)構(gòu)造器創(chuàng)建實(shí)例BeanCreatorObject1Java對(duì)象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{//使用原類型獲得方法,如果沒(méi)有找到該方法,,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ù),如果只有一個(gè)參數(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)我們得到一個(gè)屬性名為age配置屬性(<propertyname=”age”>)agesetter方法(setAge),因此需要將age的首字母變成大寫。ClassMethodClassMethod的參數(shù)類型是一個(gè)接口,而具體的參數(shù)值是該接口的實(shí)現(xiàn)類,我們就需要使用Class中的getMethods方法:給一個(gè)類型和方法名,到該類型中尋找方法名與參數(shù)的方法名一致的方法,findMethodargClass一致,判斷類型是否一致使用以上的isMethodArgs進(jìn)行判斷。如果類型一致,則馬上返回。getMethod方法:直接通過(guò)類名、方法名和方法參數(shù)類型查找方法,如果查找不到,則直接返null。getSetterMethodsetter方法。先調(diào)用getMethod方法尋找方法,如果該方法的參數(shù)類型是接口,而參數(shù)值類型是該接口的實(shí)現(xiàn)類,那么將和構(gòu)造注入一樣,找不到對(duì)應(yīng)的方法。因此在getSetterMethod方法中,再調(diào)用findMethod方法進(jìn)行查找。先得到對(duì)象的類型,再得到所有遍歷所有在bean節(jié)點(diǎn)下配置的property節(jié)點(diǎn)及其對(duì)應(yīng)的值(setProperties方法的第二個(gè)參數(shù)setter方法的字符串名字,再得到方法參數(shù)行了對(duì)象的setter方法了。PropertyHandlerObject1obj=newMap<String,Map<String,Object>properties=newHashMap<String,Object>();properties.put("name","yangenxiong");//School是普通的Java對(duì)象Schoolschool=newSchool();",PropertyHandlerObject1newObj=(PropertyHandlerObject1)handler.setProperties(obj,properties);最后兩行的打印,PropertyHandlerObject1School對(duì)象和我們所創(chuàng)建(new)School試代碼中,PropertyHandlerObject1需要為name、ageschoolsetter方法,方法名分別是setName、setAge和setSchool。到,則調(diào)用setter方法進(jìn)行設(shè)值,沒(méi)有找到就忽略,這樣就可以實(shí)現(xiàn)自動(dòng)裝配,不再需要進(jìn)行任何的property配置。這樣做的好處在于,可以簡(jiǎn)化配置文件,但是同時(shí)將程序的耦合降到代碼程度,我們提供配置文件,是為了讓程序的耦合只在配置文件中體現(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)大致上實(shí)現(xiàn)了設(shè)值注入和構(gòu)造注入,在下一節(jié)中,我們編寫IoC容器的主體代碼。14.5bean14.6的設(shè)值注入代碼,為對(duì)象設(shè)置相我們需要?jiǎng)?chuàng)建一個(gè) 根據(jù)id@paramidbean節(jié)點(diǎn)的IoC容器中是否包含id@param@returntrue判斷一個(gè)bean@paramidbean節(jié)點(diǎn)的@return如果該bean是單態(tài)的,返回獲得beanbean@paramidbean節(jié)點(diǎn)的@return找到的bean}getBeanbeanidIoCbean的實(shí)例,如果查找不到,則嘗試進(jìn)行創(chuàng)建該bean的實(shí)例。AbstractApplicationContext中,我們暫時(shí)提供空實(shí)現(xiàn),現(xiàn)在新建一個(gè)方法,用于處理讀取的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)建類實(shí)例的接口和類屬性的處理接口,我們?cè)谇懊鎺坠?jié)中已經(jīng)對(duì)這些接口進(jìn)行14.4DocumentHolderElementLoader接口,DocumentDocumentElement對(duì)象進(jìn)行緩存,這里的ElementbeanDTDbeans節(jié)點(diǎn)下bean0DocumentElement對(duì)象,那么實(shí)現(xiàn)containsBean方法和isSingleton方法就十分簡(jiǎn)單,以下為兩個(gè)方法的實(shí)現(xiàn)。publicpublicbooleancontainsBean(Stringid)//ElementLoader對(duì)象根據(jù)idElementElemente=elementLoader.getElement(id);return(e==null)?false:true;}Elemente=elementLoader.getElement(id);return}接口主要用于處理Element對(duì)象的解析,具體的使用在本章的14.4.3中的詳細(xì)說(shuō)明。性中進(jìn)行緩存,因此我們需要從所有的Element中查找。bean實(shí)例,如果查找不到,那么就進(jìn)行創(chuàng)建。創(chuàng)建的順序是先根據(jù)構(gòu)造器來(lái)創(chuàng)建實(shí)例,再對(duì)該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í)例并設(shè)置屬性如果找不到該beanElement對(duì)象,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é)點(diǎn)下面所有constructor-arg節(jié)點(diǎn)的值,constructor-argrefbeanvalue節(jié)點(diǎn)的值,通過(guò)調(diào)用ElementReader接口的getConstructorValue方法取得所有的值對(duì)象集合,getConstructorValue方法已經(jīng)幫我們將這些值封裝成DataElement對(duì)象,再判斷DataElement的類型,如果是再次調(diào)用getBean方法得到容器中的bean實(shí)例,實(shí)際上這里是遞歸調(diào)用。具體getConstructorValue方法的實(shí)現(xiàn)與使用,請(qǐng)看14.4.8中該方法的詳細(xì)描述。instanceElementbean的實(shí)例,這里使用了構(gòu)造器createBeanUseDefaultConstructconstructor-arg節(jié)點(diǎn)參數(shù)不為0,就調(diào)用本類中的getConstructArgs方法獲得參數(shù),再調(diào)用BeanCreator的使用,請(qǐng)參看本章14.5節(jié)。Elementinstancebean的實(shí)例,再被設(shè)置為單態(tài)的,如果被設(shè)置為單態(tài)的(beansingletontrue),那么就將對(duì)象一種是通過(guò)名字自動(dòng)裝配,另外一種是不自動(dòng)裝配,因此就需要進(jìn)行判斷。以上是對(duì)AbstractApplicationContext中的createBean方法的補(bǔ)充。////bean實(shí)例并設(shè)置屬性如果找不到該beanElement對(duì)象,protectedObjectcreateBean(Stringid){if(e==null)thrownewBeanCreateException("elementnotfound"+id);Objectresult=instance(e);,Autowireautowire=elementReader.getAutowire(e);if(autowireinstanceofByNameAutowire){}elseif(autowireinstanceofNoAutowire),}return}自動(dòng)裝配一個(gè)對(duì)象得到該beansetter方法,再?gòu)娜萜髦胁檎覍?duì)應(yīng)的@paramMap<String,Method>methods=for(Strings:methods.keySet())Elemente=//沒(méi)有對(duì)應(yīng)的元素配置if(e==null)Objectbean=////獲得MethodMethodmethod=}}protectedvoidsetterInject(Objectobj,Elemente)//property節(jié)點(diǎn)下面的值refbean屬性和value//調(diào)用本類的getPropertyArgs方法裝參數(shù)集合重新封裝成Map}),{Map<String,Object>result=newHashMap<String,Object>();for(PropertyElementp:properties){if(deinstanceofRefElement){//bean的實(shí)例,再設(shè)置入map}elseif(deinstanceofValueElement)}}return}對(duì)應(yīng)的bean。PropertyHandler接口的實(shí)現(xiàn)與使用,請(qǐng)看本章的14.6.1節(jié)。后,再調(diào)用setter方法將bean設(shè)值到這個(gè)實(shí)例中。該方法中使用了PropertyHandler的getSetterMethodsMapexecuteMethod14.6.2節(jié)(byName節(jié)點(diǎn)的ref節(jié)點(diǎn)類似(AbstractApplicationContext類中的getConstructArgs方法。getBeangetBeanIgnoreCreate的接口方法沒(méi)有實(shí)現(xiàn)了,該方法十{return}AbstractApplicationContext是一個(gè)抽象類,并不可以實(shí)例化,因此我們?yōu)樗砑右粋€(gè)子類{publicXmlApplicationContext(String[]xmlPaths)}}XmlApplicationContextxml文件的路徑,得到參數(shù)后,再調(diào)個(gè)創(chuàng)建bean的方法,當(dāng)加載完配置文件后,就馬上啟動(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來(lái)創(chuàng)建IoC容器:ApplicationContextApplicationContextctx=new(new//拿到test1,//拿到test1,getBeanbeanid和過(guò)調(diào)用bean的無(wú)參數(shù)構(gòu)造器來(lái)創(chuàng)建實(shí)例。下面我們測(cè)試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對(duì)象,XmlApplicationContextObject2中有一個(gè)屬性叫object1XmlApplicationContextObject1類型。<bean以上的配置中,object1不自動(dòng)裝配,test4使用自動(dòng)裝配,XmlApplicationContextObject1對(duì)象里面沒(méi)有任何的屬性,XmlApplicationContextObject3的屬性如下:{privateStringname;privateintage;}以上的測(cè)試代碼中,先從容器中得到一個(gè)XmlApplicationContextObject3對(duì)象,再通過(guò)該對(duì)象的getObject1方法得到XmlApplicationContextObject1對(duì)象,再?gòu)娜萜髦型ㄟ^(guò)getBean方法得到XmlApplicationContextObject1hashCode器中的bean設(shè)置到實(shí)例里面。<beanid="test6"<property<value<property<value<property<property<ref注意:我們?cè)诒竟?jié)中所使用的XmlApplicationContextObject1、XmlApplicationContextObject2XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1obj2=(XmlApplicationContextObject1)ctx.getBean("object1");hashCodegetBeanhashCode一致。以上的配置只有一個(gè)bean,該bean是需要延遲加載的,我們可以調(diào)用ApplicationContext的//test5//test5是延遲加載的getBean方法beanObjectobj=ctx.getBeanIgnoreCreate("test5");obj=<beanid="test1"<beanid="test1"beanXmlBeanFactorybean不會(huì)ApplicationContextApplicationContextctx=newXmlBeanFactory(new們編寫的這個(gè)IoC所帶來(lái)的好處。beanIoC容器幫我們?nèi)?chuàng)建它們的實(shí)例和對(duì)它們進(jìn)行管理,我newIoC容器帶我們帶來(lái)的好處。在閱讀本節(jié)前,可以先去了解第9章圖書進(jìn)存銷系統(tǒng)的分層結(jié)構(gòu)。JPanelJFrame對(duì)14.1中我們可以看到,圖書進(jìn)存銷系統(tǒng)中,各個(gè)視圖對(duì)象里面都有一個(gè)或者多個(gè)業(yè)務(wù)層接口對(duì)象做成bean,并注入到Mai
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版建筑材料購(gòu)銷合同書模板
- 二零二五年度臺(tái)球室租賃及品牌形象合作合同3篇
- 2025購(gòu)銷合同常用文本
- 二零二五年度全新租賃房屋合同住宅押金退還管理協(xié)議3篇
- 2025年度全新出售房屋買賣貸款擔(dān)保合同3篇
- 2025年度年度全新高空纜車運(yùn)營(yíng)意外事故免責(zé)服務(wù)協(xié)議3篇
- 二零二五年度智慧社區(qū)建設(shè)與運(yùn)營(yíng)管理協(xié)議合同范文2篇
- 2025年農(nóng)村兄弟分家協(xié)議及遺產(chǎn)分配執(zhí)行方案
- 2025年度養(yǎng)殖場(chǎng)勞務(wù)合同(養(yǎng)殖場(chǎng)安全生產(chǎn)監(jiān)管)3篇
- 二零二五年度創(chuàng)業(yè)投資股權(quán)代持專項(xiàng)合同2篇
- 《特種設(shè)備重大事故隱患判定準(zhǔn)則》知識(shí)培訓(xùn)
- 山東省棗莊市滕州市2023-2024學(xué)年高二上學(xué)期期末考試政治試題 含答案
- 《外盤期貨介紹》課件
- 2024年07月11396藥事管理與法規(guī)(本)期末試題答案
- 《PMC培訓(xùn)資料》課件
- 2025年初級(jí)社會(huì)工作者綜合能力全國(guó)考試題庫(kù)(含答案)
- 企業(yè)發(fā)展培訓(xùn)
- 江蘇省徐州市2023-2024學(xué)年高一上學(xué)期1月期末抽測(cè)試題 化學(xué) 含答案
- 紅藍(lán)光譜治療儀
- 軍事理論-綜合版智慧樹(shù)知到期末考試答案章節(jié)答案2024年國(guó)防大學(xué)
- 2024年時(shí)事政治熱點(diǎn)題庫(kù)200道含完整答案(必刷)
評(píng)論
0/150
提交評(píng)論