aixom教程.docx
- 文档编号:18476678
- 上传时间:2023-08-18
- 格式:DOCX
- 页数:13
- 大小:34.20KB
aixom教程.docx
《aixom教程.docx》由会员分享,可在线阅读,更多相关《aixom教程.docx(13页珍藏版)》请在冰点文库上搜索。
aixom教程
AXis对象模型(AXisObjectModel,AXIOM)是ApacheAxis2的XML对象模型,其目标是提供强大的特性组合彻底改变XML处理技术。
AXIOM超越了现有的XML处理技术,它把延迟构建和一种快速、轻型的可定制对象模型结合了起来。
本文中,软件架构师、AXIOM的首创者EranChinthaka介绍了这种新的XML处理方法。
AXIOM还不是另一种对象模型。
它有着明确的设计目标:
大幅提升Apache下一代SOAP协议栈Axis2的性能。
结果造就了不同于其他对象模型的AXIOM(也称为OM),因为它突出了构造的轻型,并且仅当需要的时候才建立。
由于是轻型的,它尽可能地减轻对系统资源的压力,特别是CPU和内存。
同时,延迟构造又允许在其他部分还没有完成的时候使用树的一部分。
AXIOM强大的延迟构建能力源于底层的StreamingAPIforXML(StAX)解析器。
AXIOM提供了所有这些特性,同时幕后的复杂性对用户是透明的。
使用XMLBenchDocumentModelBenchmark测试(请参阅参考资料)的结果表明,AXIOM的性能和现有的高性能对象模型相当。
但是AXIOM的内存占用要好于现有多数依靠SAX和/或DOM输入输出的对象模型。
因此对于Web服务引擎或内存受限制设备这样的XML处理器,AXIOM是一种理想的选择,它可用于一般的XML处理,但是有一个对SOAP优化了的可选层。
使用AXIOM
在典型的SOAP引擎中,数据可能以三种不同的方法表示:
∙序列化形式,如XML或二进制XML。
∙内存中基于树的对象模型,如DOM。
∙专用于特定语言的对象,如PlainOldJavaObject(POJO)。
比如一个Web服务的调用。
传递给服务提供商的数据可能是用语言专用的对象,对于Java技术就是POJO。
调用过程的第一步是将这些对象中的信息项放入SOAP信封,构造一个SOAP消息。
因为SOAP消息是XML文档,所以Web服务还必须将数据项转化成要求的XML格式。
在内存中表示XMLInfoset需要构造一个对象树,供对象模型(AXIOM)使用。
从头创建AXIOM
创建内存对象层次结构的第一步是创建一个对象工厂:
OMFactoryfactory=OMAbstractFactory.getOMFactory();
AXIOM允许很多不同的对象工厂实现,但链表是最常用的。
一旦建立了工厂,就可以开始构造树了。
比如下面的XML片段:
清单1.Lineitem细节
line-itempo: quantity="2" xmlns: po="http: //openuri.org/easypo"> description> Burnham'sCelestialHandbook,Vol2 description> price>19.89 price>
line-item>
注意,所有的元素和属性都属于"http:
//openuri.org/easypo"名称空间。
因此,为这个XML片段构造AXIOM树的第一步就是创建名称空间,如下所示:
OMNamespacepoNs=factory.createOMNamespace("http:
//openuri.org/easypo","po");
现在可以构造包装器元素line-item了:
OMElementlineItem=factory.createOMElement("line-item",poNs);
接下来创建line-item元素相关的子元素和属性。
最好用下面的方式创建元素属性:
lineItem.addAttribute("quantity","2",poNs);
与其他元素一样创建子元素,然后按照下面的方式结合到父元素中:
OMElementdescription=factory.
createOMElement("description",poNs);
description.setText("Burnham'sCelestialHandbook,Vol2");
lineItem.addChild(description);
类似地,也添加price子元素:
OMElementprice=factory.createOMElement("price",poNs);
price.setText("19.89");
lineItem.addChild(price);
清单2显示了完整的代码片段。
清单2.通过程序创建lineitem
OMFactoryfactory=OMAbstractFactory.getOMFactory();
OMNamespacepoNs=
factory.createOMNamespace("http:
//openuri.org/easypo","po");
OMElementlineItem=
factory.createOMElement("line-item",poNs);
lineItem.addAttribute("quantity","2",poNs);
OMElementdescription=
factory.createOMElement("description",poNs);
description.setText("Burnham'sCelestialHandbook,Vol2");
lineItem.addChild(description);
OMElementprice=factory.createOMElement("price",poNs);
price.setText("19.89");
lineItem.addChild(price);
输出
现在可以使用StAXwriter来序列化构造好的元素:
清单3.序列化lineitem
XMLOutputFactoryxof=XMLOutputFactory.newInstance();
XMLStreamWriterwriter=xof.
createXMLStreamWriter(System.out);
lineItem.serialize(writer);
writer.flush();
从已有代码构造AXIOM
现在看看相反的过程,从数据流建立内存对象模型。
最简单的情况下,只需要关心XML片段的反序列化。
但是在SOAP处理中,需要反序列化SOAP消息或者经过MTOM优化的MIME信封。
因为与SOAP处理关系特别密切,所以AXIOM为此提供内置支持,稍候将详细介绍。
但首先要说明如何反序列化简单的XML片段,具体来说就是刚刚序列化的那个XML片段。
首先构造一个解析器。
AXIOM支持用SAX和StAX解析器解析XML。
但是,SAX解析不允许对象模型的延迟构造,因此在延迟构建很重要时,应该使用基于StAX的解析器。
第一步是为数据流获得一个XMLStreamReader:
Filefile=newFile("line-item.xml");
FileInputStreamfis=newFileInputStream(file);
XMLInputFactoryxif=XMLInputFactory.newInstance();
XMLStreamReaderreader=xif.createXMLStreamReader(fis);
然后创建一个builder并将XMLStreamReader传递给它:
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
lineItem=builder.getDocumentElement();
现在可以使用AXIOMAPI来访问属性和子元素或者XMLInfoset项了。
可以这样访问属性:
OMAttributequantity=lineItem.getFirstAttribute(
newQName("http:
//openuri.org/easypo","quantity"));
System.out.println("quantity="+quantity.getValue());
用类似的方式访问子元素:
price=lineItem.getFirstChildWithName(
newQName("http:
//openuri.org/easypo","price"));
System.out.println("price="+price.getText());
清单4显示了完整的代码片段。
清单4.从XML文件构建AXIOM
Filefile=newFile("line-item.xml");
FileInputStreamfis=newFileInputStream(file);
XMLInputFactoryxif=XMLInputFactory.newInstance();
XMLStreamReaderreader=xif.createXMLStreamReader(fis);
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
OMElementlineItem=builder.getDocumentElement();
lineItem.serializeWithCache(writer);
writer.flush();
OMAttributequantity=lineItem.getFirstAttribute(
newQName("http:
//openuri.org/easypo","quantity"));
System.out.println("quantity="+quantity.getValue());
OMElementprice=lineItem.getFirstChildWithName(
newQName("http:
//openuri.org/easypo","price"));
System.out.println("price="+price.getText());
OMElementdescription=lineItem.getFirstChildWithName(
newQName("http:
//openuri.org/easypo","description"));
System.out.println("description="+description.getText());
AXIOM最好的一点是,努力在延迟构造这类高端技术上提供用户友好的API。
但是要充分发挥其潜能,必须了解底层体系结构。
回页首
进一步考察AXIOM
缓冲是AXIOM的核心概念之一。
但是,要理解缓冲必须在树的延迟构造和AXIOMAPI上下文中来思考。
AXIOM提供多种访问底层XMLInfoset的API。
上面使用的是基于树的API,所有其他竞争的对象模型如DOM和JDOM都提供了这样的API。
但是,AXIOM还允许通过SAX或StAXAPI访问信息。
如图1所示。
图1.AXIOM,输入和输出
如果要使用一种XML解析API,为何还要构造对象模型呢?
为了使用不同API访问对象模型的不同部分。
比如,考虑SOAP栈的情况:
SOAP消息在被目标服务消费之前可能会经过多个处理程序的处理。
这些处理程序通常使用基于树的API(特别是SOAPwithAttachmentsAPIforJava,或SAAJ)。
服务实现还可能使用数据绑定工具将SOAP消息负荷中的XML文档转化成对象,如POJO。
因为用户不使用基于树的对象模型来访问这部分文档,所以构造完整的树会因为数据重复而浪费内存。
最直接的解决方法是向数据绑定工具公开底层的原始XML流。
这就是AXIOM的闪光之处。
为了获得最佳的性能和内存使用,需要让数据绑定工具直接访问底层的XML流。
AXIOM完全允许这样做。
延迟构建仅仅意味着只有在访问的时候才构造要访问的这部分树。
因此如果不需要访问SOAP消息体,SOAP消息的这部分就不会被构建。
如果用户开始使用SAX或StAX访问消息体,而它还没有构建,AXIOM将把用户直接连接到底层的解析器,以便提供最佳的性能。
如图2所示:
图2.通过AXIOM访问底层的解析器
但是,如果用户希望再回来访问树的同一部分就可能出现问题。
因为解析器已经直接连接了用户,AXIOM退出了,就是说所有信息都从低层的流直接流向用户。
因此当用户回来请求同样的信息时,无论第二次选择什么样的API,AXIOM都不能提供该信息。
注意这两种可能性差不多相等。
比如,多数情况下SOAP体的处理中只有最终的服务实现才会涉及到负荷。
服务可以使用数据绑定或其他XML处理API如SAX、StAX或XPath来处理消息体。
这种情况下,消息体很少被访问两次,AXIOM提供的优化具有最好的性能。
但是,假设在处理程序链中插入一个日志处理程序,使用StAXwriter记录整个SOAP消息。
如果服务实现尝试访问消息体,而消息体不存在!
为了进一步说明这一点,下面是一个比较简单的例子,虽然有点牵强。
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
lineItem=builder.getDocumentElement();
lineItem.serialize(writer);
writer.flush();
price=lineItem.getFirstChildWithName(
newQName("http:
//openuri.org/easypo","price"));
System.out.println("price="+price.getText());
由于延迟构造,获得lineItem元素的时候该元素还没有构造完成。
因此后面使用StAXwriter进行序列化时,AXIOM把StAXwriter(它序列化lineItem元素)直接连接到StAXreader(它最初被传递给builder)。
但是这个过程中,AXIOM断开了自身和数据流的连接。
现在当请求price子元素的时候,找不到这样的元素,因为lineItem的所有子元素都在序列化器中消失了。
这种情况下,惟一的办法是避免序列化过程中AXIOM完全和数据流脱离开。
用AXIOM的术语称为缓冲:
无论是否在内存中建立了对象模型,AXIOM都允许获得StAX事件或者序列化XML。
因此,AXIOM把策略(比如是否应该缓冲消息)和机制(如何缓冲)分离开来。
它允许用户在开始使用原始XML处理API(如SAX或StAX)时决定是否缓冲树中未用到的部分以供将来引用。
如果用户决定这样做,当树构造完成时可以再回来访问这些部分。
但是,用户必须付出内存占用和性能的代价。
另一方面,如果用户了解自己的目标,并确信只此一次需要访问树的这些部分,则可以选择关闭缓冲来充分发挥AXIOM的效率。
因此,上一段代码应改写为:
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
lineItem=builder.getDocumentElement();
lineItem.serializeWithCache(writer);
writer.flush();
price=lineItem.getFirstChildWithName(
newQName("http:
//openuri.org/easypo","price"));
System.out.println("price="+price.getText());
方法serializeWithCache与对应的serialize不同,不会将StAXreader直接连接到StAXwriter。
相反,从reader传递给writer的所有数据都保留在AXIOM中。
具体如何缓冲与用户无关。
目前如果启用缓冲,AXIOM就会像用户在通过文档API访问树的这些部分一样构造树。
回页首
AXIOM和StAX
了解这些背景之后,现在看看AXIO的StAXAPI。
该API中最重要的方法如下:
(OMElement).getXMLStreamReader();
(OMElement).getXMLStreamReaderWithoutCaching();
通过StAXAPI对某个元素调用第一个方法,可以访问该元素的XMLInfoset,同时缓冲(如果需要)树中未构造的部分以供将来使用。
顾名思义,第二个方法用于访问同样的信息,但是通过关闭缓冲机制优化了性能。
在编写需要使用数据绑定框架的存根和skeleton程序时,这是最有用的方法。
但是请注意,如果在调用上述方法之前已经建立了树,AXIOM将模拟StAX解析器。
因此有些树节点的事件是通过模拟而来的,而对于另一些节点则直接连接到底层的解析器。
AXIOM的优点在于这些内部处理对用户是透明的。
但是,在切换到原始API时,必须指明是否需要缓冲数据。
为了说明StAXAPI的用法,我将展示如何使用XMLBeans生成的代码连接到AXIOM。
清单5.XMLBeans生成的订单代码
publicclassPurchaseOrderSkel{
publicvoidsubmitPurchaseOrder(
PurchaseOrderDocumentdoc)throwsException{
}
publicvoidsubmitPurchaseOrderWrapper(
OMElementpayload){
try{
XMLStreamReaderreader=payload.
getXMLStreamReaderWithoutCaching();
PurchaseOrderDocumentdoc
=PurchaseOrderDocument.Factory.parse(reader);
submitPurchaseOrder(doc);
}catch(Exceptionex){
ex.printStacktrace();
}
}
}
清单5中的代码(通常用代码生成工具生成)展示了一个skeleton,它使用XMLBeans生成的类(即PurchaseOrderDocument)进行数据绑定。
这个skeleton包含两个服务实现方法。
第一个允许服务实现者使用数据绑定对象,第二个则允许直接访问AXIOMAPI。
主要看看这几行:
XMLStreamReaderreader=payload.
getXMLStreamReaderWithoutCaching();
PurchaseOrderDocumentdoc
=PurchaseOrderDocument.Factory.parse(reader);
为了创建对象,首先对SOAP栈(如ApacheAxis)压入服务实现的载荷获得对StAXAPI的引用。
因为现在在处理链的最末端,所以可以安全地把解析器直接连接到XMLBeans解除封送器以获得最佳性能。
对于清单5中的skeleton,其存根代码类似于清单6。
清单6.存根代码
publicclassPurchaseOrderStub{
publicvoidsubmitPurchaseOrder(
PurchaseOrderDocumentdoc)throwsException{
SOAPEnvelopeenvelope=factory.getDefaultEnvelope();
XMLStreamReaderreader=doc.newXMLStreamReader();
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
OMElementpayload=builder.getDocumentElement();
envelope.getBody().addChild(payload);
//...
}
}
主要看看这几行:
XMLStreamReaderreader=doc.newXMLStreamReader();
StAXOMBuilderbuilder=newStAXOMBuilder(reader);
Elementpayload=builder.getDocumentElement();
从这段代码可以看出,经过StAXAPI从对象到AXIOM,与从XML到AXIOM没有什么区别。
但是初看起来不那么明显的是延迟构造仍然在起作用!
即使在将载荷插入SOAP信封的过程中创建了OMElement,内存中也没有重复的信息项。
这是由于延迟构造和AXIOM内的多路技术造成的,它将从一个API输入的数据直接转发给另一个API输出。
当消息最终写入流的时候,XMLBeans提供的XMLStreamReader直接连接到传输writer,后者将消息写入套接字——假设此过程中没有要查看消息的处理程序。
这意味着直到此时,数据仍然存放在XMLBeans对象中,真是好极了!
回页首
AXIOM和数据绑定
这里讨论AXIOM的SAXAPI,因为有些数据绑定框架不能使用其他的API,比如JAXB。
虽然上述情况下使用SAX显然不会达到最佳性能,但从AXIOM到对象使用SAX并没有造成性能损失,因为这一步在任何情况下都是必需的。
如果使用JAXB,那么存根程序就要使用SAXOMBuilder从数据绑定对象建立AXIOM。
清单7示范了这个过程。
清单7.AXIOM和JAXB
publicclassP
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- aixom 教程