疯狂java实例第14章 自己开发IoC容器Word文档格式.docx
- 文档编号:21517577
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:65
- 大小:252.77KB
疯狂java实例第14章 自己开发IoC容器Word文档格式.docx
《疯狂java实例第14章 自己开发IoC容器Word文档格式.docx》由会员分享,可在线阅读,更多相关《疯狂java实例第14章 自己开发IoC容器Word文档格式.docx(65页珍藏版)》请在冰豆网上搜索。
dom4j是一个常用的XML解析项目,该项目是一个易用的开源项目,它应用于Java平台,支持使用Dom、SAX来解析XML文件。
Dom4j的使用非常简单,只需要使用该项目所提供的解析类,就可以轻松的读取到相应的XML文件,并可以得到这些xml的相关内容。
本章中我们采用了XML文件作为我们的IoC容器的配置文件,因此使用dom4j就非常的合适。
14.2.3Junit
Junit是一个单元测试框架,供Java程序员编写单元测试。
在本章中,我们每编写一个功能点,就需要对该功能进行单元测试,一来可以展示我们所编写程序的效果,二来可以保证我们的程序的质量。
如果站在XP(极限编程)的角度来讲,编写测试可以让我们的代码更加健壮,更不惧任何的变更,对我们项目的发展有长远的利益。
本章的重点是IoC容器,使用这个测试框架,目的是展示我们代码的效果,我们当前所使用的是Junit4。
14.3确定配置文件内容、编写DTD
在编写IoC容器之前,我们需要编写XML文件,这些XML文件用来定义人们IoC容器的一些配置,例如声明我们需要创建哪些对象(bean),为这些对象(bean)提供名字和类名,让我们的IoC容器根据这些信息去创建相应的bean。
除了定义bean的名字和类名外,还需要定义一些其他的属性,例如该bean是否为单态,是否需要延迟加载定。
确定了配置文件的内容后,我们开始着手编写DTD文件。
14.3.1声明bean
在整个IoC容器中,每一个bean代表具体的某个类,因此我们的根节点为beans,beans下有多个bean,可以让我们配置具体的某个类。
XML文件的具体配置如下:
<
bean>
<
/bean>
…
/beans>
定义好了bean节点好,我们需要为bean节点指定一个名字和类名,表示这个bean所对应的名称与类型,这些我们的IoC容器得到这些配置后,就可以帮我们创建这些类的实例。
具体的配置如下:
beans>
beanid=”myDate”class=”java.util.Date”>
以上的bean配置表示我们在IoC容器中创建了一个myDate的bean,该bean的类型是java.util.Date。
14.3.2声明单态的bean
定义一个bean除了需要显式声明该bean的名称和类型外,还需要告诉我们的IoC容器,该bean是否为单态,如果该bean是单态的话,那么IoC容器在启动的时候,就只会为该bean创建一个实例,并将该实例缓存起来,如果该bean配置成非单态的话,那么就不进行缓存,每次请求这个bean的时候,就重新创建一个。
我们为bean的配置添加一个singleton属性,用来声明bean是否为单态。
beanid=”myDate”class=”java.util.Date”singleton=”false”>
以上配置的黑体部分,我们配置了myDate这个bean为非单态,在一般的情况下,我们可以不指定singleton属性,让singleton属性在不显式声明的情况下的值为true,给配置节点提供默认值,在14.4准备DTD文件中有详细说明。
14.3.3声明延迟加载
当IoC容器启动的时候,容器是否需要马上创建这个bean,我们可以为配置文件提供一个属性,让容器知道我们在容器初始化的时候,是否需要创建。
我们为bean提供一个lazy-init的属性:
beanid=”myDate”class=”java.util.Date”lazy-init=”true”>
以上的配置代码中,声明了myDate需要延迟加载,为bean节点加了这个属性后,beans节点也可以提供一个default-lazy-init的属性,表示这份配置文件下的所有bean,如果lazy-init属性的值为default的时候,就使用beans节点(根节点)的default-lazy-init所配置的值:
beansdefault-lazy-init=”true”>
beanid=”myDate”class=”java.util.Date”lazy-init=”default”/>
以上的配置,如果myDate的bean声明为default的话,那么就按照beans的default-lazy-init属性来决定是否需要延迟加载。
如果对bean的lazy-init属性不指定值的话,那么就为这个lazy-init属性指定为default,表示这个bean是否延迟加载取决于beans的配置,而beans的default-lazy-init属性不显式指定的话,可以使用false作为默认值。
14.3.4声明设值注入到bean的属性
IoC容器除了可以帮我们创建bean之外,还可以帮助我们将对应的属性设置到该bean的实例里面,我们需要为每个bean注入一些属性,让该bean的实例得到这些属性,这些属性有可能是一些普通的值,也有可能是另外的定义的bean。
在这里我们使用设值注入,设值注入,就是创建了bean的实例后,再获得该bean配置的一些属性,通过该bean里面的setter方法,设值到该bean的实例中。
!
-定义一个student的bean-->
beanid="
student"
class="
org.crazyit.Student"
>
<
-为Student类中的school属性注入school的bean-->
propertyname="
school"
<
refbean="
/>
/property>
org.crazyit.School"
以上的配置中的黑体部分,我们为student的bean注入了一个school的bean,这样,school和student这两个bean就产生了依赖关系,这样的注入我们就叫依赖注入,以上的注入方式是依赖注入中的设值注入。
那么我们的配置文件中需要为bean加入一个property的子节点,该节点里面有一个name属性,property节点下面有一个ref子节点,ref子节点指向某一个容器中的bean。
除了注入另外定义的bean外,还可以向bean中注入一些普通的属性:
age"
valuetype="
java.lang.Integer"
18<
/value>
以上的配置表示向student这个bean中注入了一个Integer的值,对应Student的age属性。
因此,property节点下面可以出现ref节点和value节点,但是,每一个property只能出现一次ref节点或者value节点,因为我们一个property只会设置一个属性。
14.3.5声明构造注入到bean的属性
14.3.4小节中,我们定义配置文件中为bean提供property节点进行设值注入,本小节我们定义构造注入的节点。
构造注入,也就是通过bean中定义的构造参数,在创建这个bean的实例时,就将这些参数通过调用该bean的构造器,将这些配置的属性传递给该bean。
constructor-arg>
/constructor-arg>
以上配置的黑体部分,声明了创建student这个bean的时候,我们需要为Student类提供一个构造器,构造器的参数为School类型,那么IoC容器在创建时,就会根据constructor-arg声明的属性,去调用Student的构造器。
与14.3.4中的设值注入一样,除了可以提供ref元素外,还可以提供value元素,构造注入一些另外的普通属性。
20<
这样的配置,我们就可以为Student进行构造注入,并在创建bean的实例时,提供一个Integer类型的构造参数。
14.3.6自动装配
自动装配,就是不需要指定bean的属性,从IoC容器中查找bean所需要的属性,将这些查找到的bean以设值注入的方式依赖注入到目标的bean中。
autowire="
byName"
org.carayit.School"
以上的student提供了autowire属性,该属性值为byName,表示根据bean的名称自动注入到student中,如果Student类中有一个setSchool的setter方法,并且参数为Schoold对象,那么容器就需要自动的将School的bean通过设值注入设置到Student中。
与延迟加载一样,也可以为beans节点提供一个default-autowire属性,声明该beans根节点下面所有的bean节点,如果autowire的值为default,那么就可以进行自动装配。
beansautowire="
default"
在本例中autowire的值我们定义为只允许为no或者byName。
如果autowire的值为no的话,表示不需要自动装配。
bean的autowire属性默认值为default。
确定了IoC的配置文件需要配置的内容,那么接下来,我们就可以根据上述的配置内容,编写相关的约束文件(DTD)。
14.3.7准备DTD文件
文档定义类型(DTD)可以定义合法的XML文档构建模块,对我们所编写的一些XML文件进行约束,也就是说,当一份XML指定了某份DTD文件时,那么该XML文件就必须遵守该DTD文件的约束。
简单的说,DTD就是一种对XML文件定制的规范。
当我们需要为一份XML定义某份DTD规范的时候,在XML文件头中声明:
?
xmlversion="
1.0"
encoding="
UTF-8"
DOCTYPEbeansPUBLIC"
-//CRAZYIT//DTDBEAN//EN"
"
http:
//www.crazyit.org/beans.dtd"
以上的XML文件头,声明了该份XML由http:
//www.crazyit.org/beans.dtd这一份dtd来约束,每个元素都需要遵守该份DTD中所声明的文档结构。
根据14.3.1到14.3.6里面定义的配置文件的内容,我们可以开始编写DTD文件。
以下为我们的IoC容器配置文件的DTD文件:
ELEMENTbeans(
bean*
)>
ATTLISTbeansdefault-lazy-init(true|false)"
false"
ATTLISTbeansdefault-autowire(no|byName)"
no"
--指定bean元素的子元素-->
ELEMENTbean(
(constructor-arg|property)*
--指定bean元素的属性值-->
ATTLISTbeanidCDATA#REQUIRED>
ATTLISTbeanclassCDATA#REQUIRED>
ATTLISTbeanlazy-init(true|false|default)"
ATTLISTbeansingleton(true|false)"
true"
ATTLISTbeanautowire(no|byName|default)"
--声明constructor-arg子元素-->
ELEMENTconstructor-arg(
(ref|value|null)
--声明property元素的子元素-->
ELEMENTproperty(
(ref|value|null)?
--声明property的属性-->
ATTLISTpropertynameCDATA#REQUIRED>
ATTLISTvaluetypeCDATA#REQUIRED>
--声明ref元素-->
ELEMENTrefEMPTY>
--声明ref的属性-->
ATTLISTrefbeanCDATA#REQUIRED>
--声明value元素-->
ELEMENTvalue(#PCDATA)>
通过以上的代码,那么该份DTD的各个节点可以概括为如下几个:
❑beans节点:
根节点为beans,beans的属性有default-lazy-init和autowire,这两个属性的默认值(不需要显式提供)为false和no。
❑bean节点:
beans下面有多个bean节点,bean节点必须要显式提供id和class属性,可以不必显式提供lazy-init,singleton和autowire属性,lazy-init的默认值为default,表示该值由beans的default-lazy-init来决定,singleton的默认值为true,而且只允许有true和false两个值,autowire属性的默认值是default,由beans的default-autowire来决定。
❑construct-arg节点:
ref、value和null都可以作为该节点的子节点,该节点没有属性。
❑property节点:
ref、value和null都可以作为该节点的子节点,property节点有一个name属性,而且是必须指定的。
❑ref节点:
该节点没有子节点,只有一个必须指定的bean属性。
❑value节点:
value节点只有一个type属性,用于指定该值的类型。
编写完DTD文件后,那么我们可以在XML的文件头中声明DTD。
“我们编写的DTD文件的绝对路径"
以上的XML文件头,表示我们使用某份DTD文件作为XML的约束,指定DTD文件路径时,我们暂时使用绝对路径,指向我们上面编写的那份DTD文件,在下面的章节中,将会讲解如何将绝对路径变成url。
14.4读取XML文件
在14.2中,我们已经确定了使用dom4j来读取XML文件,我们需要明白,当在创建一个IoC容器的时候,我们就开始读取XML文件,当取完之后,可以将XML中我们所需要的信息缓存起来,也就是进行一次读取即可,如果进行多次读取,那么将会影响性能。
在使用dom4j之前,我们需要下载dom4j的包,下载完包之后,可以将包放到项目的环境变量中。
dom4j的包可以从sourceforge中下到,下载的地址为:
14.4.1加载XML文件
在本小节开头,我们已经确定了只读取一次XML,那么我们就新建一个类,用于读取XML,并将读取到的Document对象缓存。
建立DocumentHolder接口。
代码清单:
code\IoC\main\org\crazyit\ioc\xml\DocumentHolder.java
publicinterfaceDocumentHolder{
//根据文件的路径返回文档对象
DocumentgetDocument(StringfilePath);
}
DocumentHolder接口只有一个方法,用于获得一个Document对象,参数是XML文件的路径。
为该接口新建一个实现类XmlDocumentHolder。
code\IoC\main\org\crazyit\ioc\xml\XmlDocumentHolder.java
publicclassXmlDocumentHolderimplementsDocumentHolder{
//新建一个Map对象,用于保存读取到的多份XML文件
privateMap<
String,Document>
docs=newHashMap<
();
publicDocumentgetDocument(StringfilePath){
Documentdoc=this.docs.get(filePath);
if(doc==null){
this.docs.put(filePath,readDocument(filePath));
}
returnthis.docs.get(filePath);
}
//根据文件路径读取Document
privateDocumentreadDocument(StringfilePath){
try{
//使用SAXReader来读取xml文件
SAXReaderreader=newSAXReader(true);
//使用自己的EntityResolver
reader.setEntityResolver(newIoCEntityResolver());
FilexmlFile=newFile(filePath);
//读取文件并返回Document对象
Documentdoc=reader.read(xmlFile);
returndoc;
}catch(Exceptione){
e.printStackTrace();
thrownewDocumentException(e.getMessage());
以上代码中,我们使用了一个Map对象来保存多个Document对象,当外界使用getDocument方法的时候,直接从Map对象中获取该Document对象,如果取到就返回,如果取不到该对象,就通过私有方法readDocument来读取。
注意以上代码的黑体部分,我们使用了自定义的EntityResolver对象,IoCEntityResolver的代码如下。
code\IoC\main\org\crazyit\ioc\xml\IoCEntityResolver.java
publicclassIoCEntityResolverimplementsEntityResolver{
publicInputSourceresolveEntity(StringpublicId,StringsystemId)
throwsSAXException,IOException{
//先从本地寻找dtd
if("
.equals(systemId)){
InputStreamstream=IoCEntityResolver.class.
getResourceAsStream("
/org/crazyit/ioc/beans/beans.dtd"
);
returnnewInputSo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 疯狂java实例第14章 自己开发IoC容器 疯狂 java 实例 14 自己 开发 IoC 容器