疯狂java实战演义源码第14章自己开发ioc容器_第1页
疯狂java实战演义源码第14章自己开发ioc容器_第2页
疯狂java实战演义源码第14章自己开发ioc容器_第3页
疯狂java实战演义源码第14章自己开发ioc容器_第4页
疯狂java实战演义源码第14章自己开发ioc容器_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

IoCnewnew这个类,就可以得到该实例呢?IoC的概念很好的帮助我们解决了这个问题,当我们需要在一个类中使用另外的类时,可以通过一些配置来得到该类的实现。IoCInversionofControl简称,又称控制反转,一搞清楚了控制反转的概念后,我们再来了解什么叫依赖注入。依赖注入(DependencyInjection)那么可以在IoC容器中向该类注入需要被调用的实例。而不需要关注各个组件的依赖的关系。常用的IoCSpringIoC容器、webworkIoC容器、google-guice,apache的HiveMind等。一个整合的例子,来说明IoC容器给我们带来什么样的好处。机制可以让我们动态的得到某个类型的属性、构造器和方法。Java的反射机制可以在运行时构造某一这些实例设置相应的属性,因此我们需要使用Java的反射机制。们的IoC容器的配置文件,因此使用dom4j就非常的合适。JunitJava程序员编写单元测试。在本章中,我们每编写一个功能点,就如果站在XP(极限编程)的角度来讲,编写测试可以让我们的代码更加健壮,更不惧任何的变更,对果,我们当前所使用的是Junit4。(beanbean是否为单态,是否需要延迟加载定。确定了配置文件的内容后,我们开始着手编写DTD文件。声明…个bean…与类型,这些我们的IoC容器得到这些配置后,就可以帮我们创建这些类的实例。具体的配置如下:以上的bean配置表示我们在IoC容器中创建了一个myDate的bean,该bean声明单态的beanbean的时候,就重新创建一个。我们为bean的配置添加一个singleton属性,用来声明bean是否为单态。IoCbean,我们可以为配置文件提供一个属性,让容器知道我们在容器初始化的时候,是否需要创建。我们为bean提供一个lazy-init的属性: myDatebean节点加了这个属性后,beans节点也default-lazy-initbeanbeanlazy-initlazy-init属性不显式指定的话,可以使用false作为默认值。<property<ref<property<ref<beanid="school"studentbeanschoolbean,这样,school和属性,propertyref子节点,refbean。除了注入另外定义的bean外,还可以向bean中注入一些普通的属性:<property<value<ref<ref<valuestudentbeanStudent类提供一个构Student<valueStudentbean<beanid="school"<beanid="school"studentautowirebyNamebean的名称自动注入到studentStudentsetSchoolsetterSchoold对象,那么容器SchoolbeanStudentbeansdefault,那么就可以进行自动装配。<beans<beans<beanid="school"示不需要自动装配。beanautowire属性默认值为default。的约束文件(DTD。简单的说,DTD就是一种对XML文件定制的规范。<!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认值(不需要显式提供)为false和no。bean节点:beansbean节点,beanidclass属性,可以值,autowire属性的默认值是defaultbeansdefault-autowire来决定。property节点:ref、valuenull都可以作为该节点的子节点,propertyname属<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTD<!DOCTYPEbeansPUBLIC"-//CRAZYIT//DTDDTD文件,在下面的章节中,将会讲解如何将绝对路径url。在使用d4j之前,我们需要下载do4j的包,下载完包之后,可以将包放到项目的环境变量中。mj的包可以从rere中下到,下载的地址为:hporereerecdom4iles/,本4j161。XMLXML,并将读取到的Document对象缓存。建立DocumentHolder接口。}为该接口新建一个实现类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方法进行测试,并查看结果。<beanid="test"class="JunitXmlHolderTest的结果如下:Junit可以直接写断言,在这里XMLIoCDocument得到所有的Element对象,也就是配置文件中的每一个bean。//加入一份doc的所有Element//返回全部的Element}DTD规范,因此,不用去担心XML不符合我们的要求。//Map来保存Map的keybean元素的idvaluebeanElementprivateMap<String,Element>elements=newHashMap<String,Element>();publicvoidaddElements(Documentdoc){//读取根节点beans,再得到所有的bean节点for(Elemente:eles){//bean的idStringid=}}{return}{return}}XmlDocumentHolder一样,ElementHoderImplMapElement,当调addElementDocumentElement元素(bean节点)都放到MapXMLIoC容器中,beanid必须是唯一的,否则的话,先读取的Element对象,会被后读取的名字相同的Element覆盖。<beanid="test3"class="<beanid="test4"class="StringfilePath="test/resources/ElementLoader.xml";Documentdoc=holder.getDocument(filePath);Elemente=elementLoader.getElement("test1");} 可以看到结果为4。ElementElement进行解析,得到相关的信息。例如,我们需要判断得到这些信息的。新建ElementReader接口。获得一个//beanconstructor-arg的值(包括value和ref)List<DataElement>getConstructorValue(Elementelement);//bean元素下所有property元素的值(包括value和ref)}应的Element集合。值和value的值。publicpublicinterfaceAutowireStringgetValue();}Autowirebeanautowireautowire的byNameAutowireByNameAutowire。{privateString{this.value=}{return}}NoAutowireByNameAutowire一样,这两个对象只是用于判断值的类ValueElement,前者表示一个ref的节点,后者表示一个value节点,DataElement代码如下。StringgetType();}publicclasspublicclassRefElementimplements{privateObject{this.value=}{return}{return}}ValueElement的实现与RefElement一样,在这里不写出代码。在接口中,另外还有getPropertyValuePropertyElement来表示值的类型。PropertyElement里面封装点下面除了可以有这两个节点之外,property节点还有一个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节点集合。ElementReaderImplgetAttribute{Stringvalue=element.attributeValue(name);returnvalue;}Booleansingleton=newBoolean(getAttribute(element,"singleton"));returnsingleton;}DTD文件中定义singleton属性值只能是truefalse,因此在这里不需要作处理。getAutowire方法的实现与14.4.4中的isLazy方法一致,只是getAutowire方法返回的是一个nobyNamebyType等状态时,我们可以加多一个Autowire的实现类。以下是getAutowire的实现。StringparentValue=this.getAttribute(element.getParent(),"default-autowire");if("no".equals(parentValue)){if("byName".equals(value))returnnewByNameAutowire(value);returnnewNoAutowire(value);//根节点if("no".equals(value))returnnewNoAutowire(value);returnnewByNameAutowire(value);}returnnew getConstructorValueDataElement的集合,实现相对麻烦,如果再对value节点的值进行转换。以下是getConstructorValue的实现。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;}//调用本类中的getPropertyElements取得所有的property节点List<Element>properties=getPropertyElements(element);List<PropertyElementresultnewArrayList<PropertyElement>();for(Elemente:properties){//将数据值和property元素的name属性封装成PropertyElement对象PropertyElementpenewPropertyElement(propertyNameAttdataElement);}return}getPropertyValue方法与getConstructorValue方法的实现类似,getConstructorValue是得到constructor-argvalueref节点值,getPropertyValuevalue节点refgetPropertyValuePropertyElement对象集合,PropertyElement对象中包含了DataElement和一个名字,这是由于property节点中还需要有一个name属性。beanbean的constructor-arg节点,去创建一个bean的实例。我们的配置文件中,bean节点下面可以出现多个constructor-argbeanbean的时候,就可以根据构造注入,顾名思义,就是通过构造器将对应的值(bean)XML中只需要beanconstructor-arg,并分配相应的值即可,IoC容器得到这些值后,就通过调用bean对应的Class的构造器创建该bean实例。bean的实例。分两种情况,一种是没有构造参数的情况,另外一种是配置了参//使用无参的构造器创建bean实例,}行时异常。我们先实现第一个无参数构造器创建bean的方法,该方法实现比较简单。{tryClassclazz=returnthrownewBeanCreateException("classnotfound"+}catch(Exceptione)thrownew}}ClassNotFoundException,我们将这个异常进行封装,封成我们的自定义异常。那么外界beanclass属性值,传递给该方法就可以返回对应的实例,但是前提是需要判断该bean是否有构造参数。13.5.2中,我们编写调用类的无参数构造器创建实例,如果在XML配置中,bean节点下面有ListcreateBeanUseDefineConstruce的实publicpublicObjectcreateBeanUseDefineConstruce(StringclassName,List<Object>args){try{Classclazz=Constructorconstructor=findConstructor(clazz,argsClass);returnconstructor.newInstance(args.toArray());{thrownewBeanCreateException("classnotfound"+{thrownewBeanCreateException("nosuchconstructor"+}catch(Exception{thrownew}}//获得构造器,如果没有找到,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{//循环到最后一个都没有出错,if(i==(argsClass.length-{return}}catch(Exceptione)//有一个参数类型不符合,}}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);}中一个实现,那么这样就会抛出NoSuchMethodException,我们这里直接返回null。isSameArgs方法:判断参数中第一个类型数组与第二个类型数组里面对应的类型是否相同,数组中的类型,如果全部都是类型相同,那么就返回true。findConstructorClassgetConstructor方getConstructor方法将返回调用isSameArgs方法判断,如果可以找到对应的构造器,就直接返回,否则抛出createBeanUseDefineConstrucefindConstructor方法得到相应的构造器,得到构造器后,通过Constructor对象的newInstance方法创建实例。了多态的特性,那么将不能直接找到该构造器,还要经过Class的asSubclass方法进行类型转换,如果//无参数构造器创建实例//无参数构造器创建实例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()){//得到方法的所有参数,如果只有一个参数,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}//将参数s{StringfirstWord=s.substring(0,StringupperCaseWord=}{return"set"+},privateMethodgetMethod(ClassobjClass,StringmethodName,Class{tryMethodmethod=objClass.getMethod(methodName,argClass);returnmethod;{return}}upperCaseFirstWord方法:将参数中的字符串的首字母变为大写,当我们得到一个属性名为age配置属性(<propertyname=”age”>)agesetter方法(setAge),因此需要将age的首字母变成大写。ClassMethodClassMethod的参数类型是一个接口,而具体的参数值是该接口的实现类,我们就需要使用Class中的getMethods方法:给一个类型和方法名,到该类型中寻找方法名与参数的方法名一致的方法,findMethodargClass一致,判断类型是否一致使用以上的isMethodArgs进行判断。如果类型一致,则马上返回。getMethod方法:直接通过类名、方法名和方法参数类型查找方法,如果查找不到,则直接返null。getSetterMethodsetter方法。先调用getMethod方法寻找方法,如果该方法的参数类型是接口,而参数值类型是该接口的实现类,那么将和构造注入一样,找不到对应的方法。因此在getSetterMethod方法中,再调用findMethod方法进行查找。先得到对象的类型,再得到所有遍历所有在bean节点下配置的property节点及其对应的值(setProperties方法的第二个参数setter方法的字符串名字,再得到方法参数行了对象的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对象和我们所创建(new)School试代码中,PropertyHandlerObject1需要为name、ageschoolsetter方法,方法名分别是setName、setAge和setSchool。到,则调用setter方法进行设值,没有找到就忽略,这样就可以实现自动装配,不再需要进行任何的property配置。这样做的好处在于,可以简化配置文件,但是同时将程序的耦合降到代码程度,我们提供配置文件,是为了让程序的耦合只在配置文件中体现,是否进行autowire各有利弊。始编写IoC容器的主体代码,我们本小节所编写的代码,将在14.7中详细描述用处。////setter方法mapkeysetter方法名不要setMap<String,Method>getSetterMethodsMap(Objectobj);@paramargBean参数的@parammethodbeanMa接口中的executeMethod方法执行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作为参数,最后返回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的代码,只是更关注于值设置。14.5节中的构造注入,我们已经大致上实现了设值注入和构造注入,在下一节中,我们编写IoC容器的主体代码。14.5bean14.6的设值注入代码,为对象设置相我们需要创建一个 根据id@paramidbean节点的IoC容器中是否包含id@param@returntrue判断一个bean@paramidbean节点的@return如果该bean是单态的,返回获得beanbean@paramidbean节点的@return找到的bean}getBeanbeanidIoCbean的实例,如果查找不到,则尝试进行创建该bean的实例。AbstractApplicationContext中,我们暂时提供空实现,现在新建一个方法,用于处理读取的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的接口、创建类实例的接口和类属性的处理接口,我们在前面几节中已经对这些接口进行14.4DocumentHolderElementLoader接口,DocumentDocumentElement对象进行缓存,这里的ElementbeanDTDbeans节点下bean0DocumentElement对象,那么实现containsBean方法和isSingleton方法就十分简单,以下为两个方法的实现。publicpublicbooleancontainsBean(Stringid)//ElementLoader对象根据idElementElemente=elementLoader.getElement(id);return(e==null)?false:true;}Elemente=elementLoader.getElement(id);return}接口主要用于处理Element对象的解析,具体的使用在本章的14.4.3中的详细说明。性中进行缓存,因此我们需要从所有的Element中查找。bean实例,如果查找不到,那么就进行创建。创建的顺序是先根据构造器来创建实例,再对该bean进行设值。publicpublicObjectgetBean(String{Objectbean=if(bean==null)bean=handleSingleton(id);}return}//bean,如果是单态的,则加到map中,非单态,{Objectbean=//单态的话map}return}//bean实例并设置属性如果找不到该beanElement对象,protectedObjectcreateBean(Stringid){if(e==null)thrownewBeanCreateException("elementnotfound"+id);Objectresult=instance(e);System.out.println("创建bean:"+id);returnresult;}protectedprotectedObjectinstance(Elemente)if(constructorElements.size()==0){return}else//constructor-arg子元素使用有参数构造器,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)//如果是引用元素,则直接调getBean去获取(获取不到则创建)d=(RefElement)d;StringrefId=(String)d.getValue();}}returngetConstructArgs方法:该方法得到bean节点下面所有constructor-arg节点的值,constructor-argrefbeanvalue节点的值,通过调用ElementReader接口的getConstructorValue方法取得所有的值对象集合,getConstructorValue方法已经帮我们将这些值封装成DataElement对象,再判断DataElement的类型,如果是再次调用getBean方法得到容器中的bean实例,实际上这里是递归调用。具体getConstructorValue方法的实现与使用,请看14.4.8中该方法的详细描述。instanceElementbean的实例,这里使用了构造器createBeanUseDefaultConstructconstructor-arg节点参数不为0,就调用本类中的getConstructArgs方法获得参数,再调用BeanCreator的使用,请参看本章14.5节。Elementinstancebean的实例,再被设置为单态的,如果被设置为单态的(beansingletontrue),那么就将对象一种是通过名字自动装配,另外一种是不自动装配,因此就需要进行判断。以上是对AbstractApplicationContext中的createBean方法的补充。////bean实例并设置属性如果找不到该beanElement对象,protectedObjectcreateBean(Stringid){if(e==null)thrownewBeanCreateException("elementnotfound"+id);Objectresult=instance(e);,Autowireautowire=elementReader.getAutowire(e);if(autowireinstanceofByNameAutowire){}elseif(autowireinstanceofNoAutowire),}return}自动装配一个对象得到该beansetter方法,再从容器中查找对应的@paramMap<String,Method>methods=for(Strings:methods.keySet())Elemente=//没有对应的元素配置if(e==null)Objectbean=////获得MethodMethodmethod=}}protectedvoidsetterInject(Objectobj,Elemente)//property节点下面的值refbean属性和value//调用本类的getPropertyArgs方法装参数集合重新封装成Map}),{Map<String,Object>result=newHashMap<String,Object>();for(PropertyElementp:properties){if(deinstanceofRefElement){//bean的实例,再设置入map}elseif(deinstanceofValueElement)}}return}对应的bean。PropertyHandler接口的实现与使用,请看本章的14.6.1节。后,再调用setter方法将bean设值到这个实例中。该方法中使用了PropertyHandler的getSetterMethodsMapexecuteMethod14.6.2节(byName节点的ref节点类似(AbstractApplicationContext类中的getConstructArgs方法。getBeangetBeanIgnoreCreate的接口方法没有实现了,该方法十{return}AbstractApplicationContext是一个抽象类,并不可以实例化,因此我们为它添加一个子类{publicXmlApplicationContext(String[]xmlPaths)}}XmlApplicationContextxml文件的路径,得到参数后,再调个创建bean的方法,当加载完配置文件后,就马上启动IoC容器创建tectedvoidcreateBeans()Collection<Element>elements=elementLoader.getElements();for(Elemente:elements){booleanlazy=//如果不是延迟加载if(!lazy)Objectbean=this.getBean(id);if(bean==null){//bean如果是单态的,加到缓存中,}}}}AbstractApplicationContexthandleSingleton方法创建}XMLgetBeanbean。{publicXmlBeanFactory(String[]xmlPaths)//只初始化文档,不创建任何bean}}AbstractApplicationContextIoC<bean<beanid="test1"下面的代码使用XmlApplicationContext来创建IoC容器:ApplicationContextApplicationContextctx=new(new//拿到test1,//拿到test1,getBeanbeanid和过调用bean的无参数构造器来创建实例。下面我们测试beansingleton属性(是否单态。<beanid="test1"//test1//test1是单态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设置到实例里面。<beanid="test6"<property<value<property<value<property<property<ref注意:我们在本节中所使用的XmlApplicationContextObject1、XmlApplicationContextObject2XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1XmlApplicationContextObject3obj1=(XmlApplicationContextObject3)ctx.getBean("test6");XmlApplicationContextObject1obj2=(XmlApplicationContextObject1)ctx.getBean("object1");hashCodegetBeanhashCode一致。以上的配置只有一个bean,该bean是需要延迟加载的,我们可以调用ApplicationContext的//test5//test5是延迟加载的getBean方法beanObjectobj=ctx.getBeanIgnoreCreate("test5");obj=<beanid="test1"<beanid="test1"beanXmlBeanFactorybean不会ApplicationContextApplicationContextctx=newXmlBeanFactory(new们编写的这个IoC所带来的好处。beanIoC容器帮我们去创建它们的实例和对它们进行管理,我newIoC容器带我们带来的好处。在阅读本节前,可以先去了解第9章图书进存销系统的分层结构。JPanelJFrame对14.1中我们可以看到,图书进存销系统中,各个视图对象里面都有一个或者多个业务层接口对象做成bean,并注入到Mai

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论