`
xo_tobacoo
  • 浏览: 391947 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

axis中用 AXIOM 促进 XML 处理

阅读更多

AXis 对象模型(AXis Object Model,AXIOM)是 Apache Axis 2 的 XML 对象模型,其目标是提供强大的特性组合彻底改变 XML 处理技术。AXIOM 超越了现有的 XML 处理技术,它把延迟构建和一种快速、轻型的可定制对象模型结合了起来。本文中,软件架构师、AXIOM 的首创者 Eran Chinthaka 介绍了这种新的 XML 处理方法。
AXIOM 还不是另一种对象模型。它有着明确的设计目标:大幅提升 Apache 下一代 SOAP 协议栈 Axis 2 的性能。结果造就了不同于其他对象模型的 AXIOM(也称为 OM),因为它突出了构造的轻型,并且 仅当需要的时候才建立。由于是轻型的,它尽可能地减轻对系统资源的压力,特别是 CPU 和内存。同时,延迟构造又允许在其他部分还没有完成的时候使用树的一部分。AXIOM 强大的延迟构建能力源于底层的 Streaming API for XML (StAX) 解析器。AXIOM 提供了所有这些特性,同时幕后的复杂性对用户是透明的。
使用 XMLBench Document Model Benchmark 测试(请参阅 参考资料) 的结果表明,AXIOM 的性能和现有的高性能对象模型相当。但是 AXIOM 的内存占用要好于现有多数依靠 SAX 和/或 DOM 输入输出的对象模型。因此对于 Web 服务引擎或内存受限制设备这样的 XML 处理器,AXIOM 是一种理想的选择,它可用于一般的 XML 处理,但是有一个对 SOAP 优化了的可选层。
使用 AXIOM
在典型的 SOAP 引擎中,数据可能以三种不同的方法表示:
•    序列化形式,如 XML 或二进制 XML。
•    内存中基于树的对象模型,如 DOM。
•    专用于特定语言的对象,如 Plain Old Java Object (POJO)。
比如一个 Web 服务的调用。传递给服务提供商的数据可能是用语言专用的对象,对于 Java 技术就是 POJO。调用过程的第一步是将这些对象中的信息项放入 SOAP 信封,构造一个 SOAP 消息。因为 SOAP 消息是 XML 文档,所以 Web 服务还必须将数据项转化成要求的 XML 格式。在内存中表示 XML Infoset 需要构造一个对象树,供对象模型(AXIOM)使用。
从头创建 AXIOM
创建内存对象层次结构的第一步是创建一个对象工厂:
OMFactory factory= OMAbstractFactory.getOMFactory();

AXIOM 允许很多不同的对象工厂实现,但链表是最常用的。一旦建立了工厂,就可以开始构造树了。
比如下面的 XML 片段:

清单 1.Line item 细节

<po:line-item po:quantity="2"
   xmlns:po="http://openuri.org/easypo">
      <po:description>
         Burnham's Celestial Handbook, Vol 2
      </po:description>
         <po:price>19.89</po:price>
</po:line-item>

注意,所有的元素和属性都属于 "http://openuri.org/easypo" 名称空间。因此,为这个 XML 片段构造 AXIOM 树的第一步就是创建名称空间,如下所示:
OMNamespace poNs= factory.createOMNamespace("http://openuri.org/easypo", "po");

现在可以构造包装器元素 line-item 了:
OMElement lineItem= factory.createOMElement("line-item", poNs);

接下来创建 line-item 元素相关的子元素和属性。
最好用下面的方式创建元素属性:
lineItem.addAttribute("quantity", "2", poNs);

与其他元素一样创建子元素,然后按照下面的方式结合到父元素中:
   OMElement description= factory.
      createOMElement("description", poNs);
         description.setText("Burnham's Celestial Handbook, Vol 2");
         lineItem.addChild(description);

类似地,也添加 price 子元素:
   OMElement price= factory.createOMElement("price", poNs);
         price.setText("19.89");
         lineItem.addChild(price);

清单 2 显示了完整的代码片段。

清单 2.通过程序创建 line item

   OMFactory factory = OMAbstractFactory.getOMFactory();
         OMNamespace poNs =
         factory.createOMNamespace("http://openuri.org/easypo", "po");
         OMElement lineItem =
         factory.createOMElement("line-item", poNs);
         lineItem.addAttribute("quantity", "2", poNs);
         OMElement description =
         factory.createOMElement("description", poNs);
         description.setText("Burnham's Celestial Handbook, Vol 2");
         lineItem.addChild(description);
         OMElement price = factory.createOMElement("price", poNs);
         price.setText("19.89");
         lineItem.addChild(price);

输出
现在可以使用 StAX writer 来序列化构造好的元素:

清单 3.序列化 line item

   XMLOutputFactory xof = XMLOutputFactory.newInstance();
   XMLStreamWriter writer = 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:
File file= new File("line-item.xml");
         FileInputStream fis= new FileInputStream(file);
         XMLInputFactory xif= XMLInputFactory.newInstance();
         XMLStreamReader reader= xif.createXMLStreamReader(fis);

然后创建一个 builder 并将 XMLStreamReader 传递给它:
   StAXOMBuilder builder= new StAXOMBuilder(reader);
         lineItem= builder.getDocumentElement();

现在可以使用 AXIOM API 来访问属性和子元素或者 XML Infoset 项了。可以这样访问属性:
   OMAttribute quantity= lineItem.getFirstAttribute(
         new QName("http://openuri.org/easypo", "quantity"));
   System.out.println("quantity= " + quantity.getValue());

用类似的方式访问子元素:
   price= lineItem.getFirstChildWithName(
         new QName("http://openuri.org/easypo", "price"));
               System.out.println("price= " + price.getText());

清单 4 显示了完整的代码片段。

清单 4.从 XML 文件构建 AXIOM

File file = new File("line-item.xml");
   FileInputStream fis = new FileInputStream(file);
   XMLInputFactory xif = XMLInputFactory.newInstance();
   XMLStreamReader reader = xif.createXMLStreamReader(fis);
   StAXOMBuilder builder = new StAXOMBuilder(reader);
   OMElement lineItem = builder.getDocumentElement();
   lineItem.serializeWithCache(writer);
   writer.flush();
   OMAttribute quantity = lineItem.getFirstAttribute(
         new QName("http://openuri.org/easypo", "quantity"));
   System.out.println("quantity= " + quantity.getValue());
   OMElement price = lineItem.getFirstChildWithName(
         new QName("http://openuri.org/easypo", "price"));
   System.out.println("price= " + price.getText());
   OMElement description = lineItem.getFirstChildWithName(
         new QName("http://openuri.org/easypo", "description"));
   System.out.println("description= " + description.getText());

AXIOM 最好的一点是,努力在延迟构造这类高端技术上提供用户友好的 API。但是要充分发挥其潜能,必须了解底层体系结构。

进一步考察 AXIOM
缓冲是 AXIOM 的核心概念之一。但是,要理解缓冲必须在树的延迟构造和 AXIOM API 上下文中来思考。AXIOM 提供多种访问底层 XML Infoset 的 API。上面使用的是基于树的 API,所有其他竞争的对象模型如 DOM 和 JDOM 都提供了这样的 API。但是,AXIOM 还允许通过 SAX 或 StAX API 访问信息。如图 1 所示。

图 1. AXIOM,输入和输出
 
如果要使用一种 XML 解析 API,为何还要构造对象模型呢?为了使用不同 API 访问对象模型的不同部分。比如,考虑 SOAP 栈的情况:SOAP 消息在被目标服务消费之前可能会经过多个处理程序的处理。这些处理程序通常使用基于树的 API(特别是 SOAP with Attachments API for Java,或 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 提供的优化具有最好的性能。
但是,假设在处理程序链中插入一个日志处理程序,使用 StAX writer 记录整个 SOAP 消息。如果服务实现尝试访问消息体,而消息体不存在!
为了进一步说明这一点,下面是一个比较简单的例子,虽然有点牵强。
StAXOMBuilder builder = new StAXOMBuilder(reader);
   lineItem = builder.getDocumentElement();
   lineItem.serialize(writer);
   writer.flush();
   price = lineItem.getFirstChildWithName(
      new QName("http://openuri.org/easypo", "price"));
   System.out.println("price= " + price.getText());

由于延迟构造,获得 lineItem 元素的时候该元素还没有构造完成。因此后面使用 StAX writer 进行序列化时,AXIOM 把 StAX writer(它序列化 lineItem 元素)直接连接到 StAX reader(它最初被传递给 builder)。但是这个过程中,AXIOM 断开了自身和数据流的连接。现在当请求 price 子元素的时候,找不到这样的元素,因为 lineItem 的所有子元素都在序列化器中消失了。
这种情况下,惟一的办法是避免序列化过程中 AXIOM 完全和数据流脱离开。用 AXIOM 的术语称为缓冲:无论是否在内存中建立了对象模型,AXIOM 都允许获得 StAX 事件或者 序列化 XML。因此,AXIOM 把策略(比如是否应该缓冲消息)和机制(如 何缓冲)分离开来。它允许用户在开始使用原始 XML 处理 API(如 SAX 或 StAX)时决定是否缓冲树中未用到的部分以供将来引用。如果用户决定这样做,当树构造完成时可以再回来访问这些部分。但是,用户必须付出内存占用和性能 的代价。另一方面,如果用户了解自己的目标,并确信只此一次需要访问树的这些部分,则可以选择关闭 缓冲来充分发挥 AXIOM 的效率。
因此,上一段代码应改写为:
   StAXOMBuilder builder = new StAXOMBuilder(reader);
      lineItem = builder.getDocumentElement();
      lineItem.serializeWithCache(writer);
      writer.flush();
   price = lineItem.getFirstChildWithName(
      new QName("http://openuri.org/easypo", "price"));
   System.out.println("price= " + price.getText());

方法 serializeWithCache 与对应的 serialize 不同,不会将 StAX reader 直接连接到 StAX writer。相反,从 reader 传递给 writer 的所有数据都保留 在 AXIOM 中。具体如何缓冲与用户无关。目前如果启用缓冲,AXIOM 就会像用户在通过文档 API 访问树的这些部分一样构造树。

AXIOM 和 StAX
了解这些背景之后,现在看看 AXIO 的 StAX API。该 API 中最重要的方法如下:
(OMElement).getXMLStreamReader();
(OMElement).getXMLStreamReaderWithoutCaching();

通过 StAX API 对某个元素调用第一个方法,可以访问该元素的 XML Infoset,同时缓冲(如果需要)树中未构造的部分以供将来使用。顾名思义,第二个方法用于访问同样的信息,但是通过关闭缓冲机制优化了性能。在编写 需要使用数据绑定框架的存根和 skeleton 程序时,这是最有用的方法。
但是请注意,如果在调用上述方法之前已经建立了树,AXIOM 将模拟 StAX 解析器。因此有些树节点的事件是通过模拟而来的,而对于另一些节点则直接连接到底层的解析器。AXIOM 的优点在于这些内部处理对用户是透明的。但是,在切换到原始 API 时,必须指明是否需要缓冲数据。
为了说明 StAX API 的用法,我将展示如何使用 XMLBeans 生成的代码连接到 AXIOM。

清单 5.XMLBeans 生成的订单代码

public class PurchaseOrderSkel {
   public void submitPurchaseOrder(
         PurchaseOrderDocument doc) throws Exception {
         
   }
      public void submitPurchaseOrderWrapper(
               OMElement payload) {
            try {
                  XMLStreamReader reader= payload.
                        getXMLStreamReaderWithoutCaching();
                  PurchaseOrderDocument doc
                     = PurchaseOrderDocument.Factory.parse(reader);
                           submitPurchaseOrder(doc);
            } catch (Exception ex) {
                  ex.printStacktrace();
            }
      }
   }

清单 5 中的代码(通常用代码生成工具生成)展示了一个 skeleton,它使用 XMLBeans 生成的类(即 PurchaseOrderDocument)进行数据绑定。这个 skeleton 包含两个服务实现方法。第一个允许服务实现者使用数据绑定对象,第二个则允许直接访问 AXIOM API。主要看看这几行:
                  XMLStreamReader reader= payload.
                        getXMLStreamReaderWithoutCaching();
                  PurchaseOrderDocument doc
                     = PurchaseOrderDocument.Factory.parse(reader);

为了创建对象,首先对 SOAP 栈(如 Apache Axis)压入服务实现的载荷获得对 StAX API 的引用。因为现在在处理链的最末端,所以可以安全地把解析器直接连接到 XMLBeans 解除封送器以获得最佳性能。
对于 清单 5 中的 skeleton,其存根代码类似于 清单 6。

清单 6.存根代码

public class PurchaseOrderStub {
         public void submitPurchaseOrder(
            PurchaseOrderDocument doc) throws Exception {
                  SOAPEnvelope envelope = factory.getDefaultEnvelope();
                  XMLStreamReader reader = doc.newXMLStreamReader();
                  StAXOMBuilder builder = new StAXOMBuilder(reader);
                  OMElement payload= builder.getDocumentElement();
                  envelope.getBody().addChild(payload);
                  // ...
         }
      }

主要看看这几行:
                  XMLStreamReader reader = doc.newXMLStreamReader();
                  StAXOMBuilder builder = new StAXOMBuilder(reader);
                  Element payload= builder.getDocumentElement();

从这段代码可以看出,经过 StAX API 从对象到 AXIOM,与从 XML 到 AXIOM 没有什么区别。
但是初看起来不那么明显的是延迟构造仍然在起作用!即使在将载荷插入 SOAP 信封的过程中创建了 OMElement,内存中也没有重复的信息项。这是由于延迟构造和 AXIOM 内的多路技术造成的,它将从一个 API 输入的数据直接转发给另一个 API 输出。当消息最终写入流的时候,XMLBeans 提供的 XMLStreamReader 直接连接到传输 writer,后者将消息写入套接字 —— 假设此过程中没有要查看消息的处理程序。这意味着直到此时,数据仍然存放在 XMLBeans 对象中,真是好极了!

AXIOM 和数据绑定
这里讨论 AXIOM 的 SAX API,因为有些数据绑定框架不能使用其他的 API,比如 JAXB。虽然上述情况下使用 SAX 显然不会达到最佳性能,但从 AXIOM 到对象使用 SAX 并没有造成性能损失,因为这一步在任何情况下都是必需的。
如果使用 JAXB,那么存根程序就要使用 SAXOMBuilder 从数据绑定对象建立 AXIOM。清单 7 示范了这个过程。

清单 7. AXIOM 和 JAXB

public class PurchaseOrderStub {
      public void submitPurchaseOrder(
            PurchaseOrder doc) throws Exception {
                  SOAPEnvelope envelope = factory.getDefaultEnvelope();
                  SAXOMBuilder builder = new SAXOMBuilder();
                  JAXBContext jaxbContext = JAXBContext.newInstance("po");
                  Marshaller marshaller = jaxbContext.createMarshaller();
                  marshaller.marshal(doc, builder);
                  OMElement payload= builder.getDocumentElement();
                  envelope.getBody().addChild(payload);
                  //...
      }
   }

到目前为止,AXIOM 还不允许使用 OMElement 注册内容处理程序来处理收到的 SAX 事件。不过很容易编写一段胶水代码,从提供的 StAX 接口接收事件并驱动 SAX ContentHandler。有兴趣的读者可以从 参考资料 中的 JAXB 参考实现中找到这样的实现。


结束语
我介绍了与典型的 XML 对象模型相比 AXIOM 引入的一些很有前途的特性。注意本文仅仅介绍了部分特性。AXIOM 有很多更强大的特性,建议您从 Axis 2 源代码库(请参阅 参考资料)下载最新的源代码,进一步研究 AXIOM。

分享到:
评论

相关推荐

    axis2 axiom api 文档

    它有着明确的设计目标:大幅提升 Apache 下一代 SOAP 协议栈 Axis 2 的性能。结果造就了不同于其他对象模型的 AXIOM(也称为 OM),因为它突出了构造的轻型,并且 仅当需要的时候才建立. 这里是它的api 文档

    axis2所用jar包大全下载

    Axis2的基本运行时库包括了`axis2-*.jar`文件,例如`axis2-adb.jar`、`axis2-kernel.jar`等,它们提供了Axis2的核心功能,如服务部署、消息处理和模块管理。`adb`代表“抽象数据绑定”,它是Axis2的一种数据绑定机制...

    axiom api

    通过其高效的DOM实现、流式处理能力和与 Axis2 的紧密集成,Axiom在XML和SOAP应用开发中扮演着至关重要的角色。提供的apidocs文件很可能是Axiom API的官方文档,其中包含了详细的接口说明和使用示例,对于理解和使用...

    axis2相关的jar包

    axiom-api-1.2.10.jar axiom-dom-1.2.10.jar axiom-impl-1.2.10.jar axis2-adb-1.5.4.jar axis2-adb-codegen-1.5.4.jar axis2-codegen-1.5.4.jar axis2-corba-1.5.4.jar axis2-fastinfoset-1.5.4...XmlSchema-1.4.3.jar

    axis配置指南 service.xml形式

    本篇文章将详细阐述 Axis2 的配置机制,特别是关注服务配置文件 `service.xml` 的使用。 首先,我们了解 Axis2 的三种配置文件类型: 1. **全局配置 (axis2.xml)**: 这是配置整个 Axis2 环境的文件,包含了系统级...

    axiom API文档,javadoc格式排版

    Axiom的主要目标是提供一种高效、灵活且易于使用的API,使得开发者能够方便地处理XML数据,特别是在Web服务开发中,Axiom是Apache Axis2框架的重要组成部分。 **知识点二:Javadoc** Javadoc是一种由Java语言官方...

    Axis2之使用services.xml发布带包的Webservice

    标题中的“Axis2之使用services.xml发布带包的Webservice”指的是在Apache Axis2框架下,通过services.xml配置文件来发布包含多个类或包的Web服务。Apache Axis2是Java平台上的一个开源Web服务框架,它允许开发人员...

    Axis2的OMElement SOAP XML报文节点首字母小写转大写(注意,是节点,不是节点元素的值) java

    当我们处理SOAP XML报文时,有时会遇到需要转换XML节点名的情况,例如将节点名的首字母从小写转换为大写。以下将详细探讨这个主题。 首先,理解XML节点和节点元素的区别是至关重要的。在XML文档中,节点可以是元素...

    java连接webservice,axis2实现方式所需jar包

    4. **axiom-api-1.2.13.jar**和**axiom-impl-1.2.13.jar**:AXIOM(Abstract XML Information Model)是Apache的一个XML信息模型,提供了处理XML文档的API。API文件包含接口,而Impl文件包含具体的实现。 5. **...

    axiom-api-1.2.1.jar.zip

    总之,"axiom-api-1.2.1.jar.zip"是Apache Axiom API的一个版本,它提供了强大的XML处理能力,适用于需要高效处理XML数据的Java项目。通过正确地导入和使用这个库,开发者能够简化XML操作,提升项目的可维护性和性能...

    axis 1.x与axis2.x开发

    Axis2.x基于AXIOM(Abstract XML Information Model)和Axiom组件,提供了更高效的消息处理机制。AXIOM是一个高性能的XML信息模型,允许对XML数据进行低级别操作,提高了处理速度。此外,Axis2.x采用了模块化架构,...

    axis1.4和axis2相关jar文件

    2. **效率提升**:通过使用基于XML流处理的Axiom库,Axis2提高了处理大量XML数据时的性能。 3. **多协议支持**:除了SOAP 1.1,Axis2还支持SOAP 1.2,甚至RESTful服务,以及WS-*家族的多种标准,如WS-Security、WS-...

    Axis2三种配置文件

    3. **module.xml** - 模块是Axis2中可重用的功能单元,它们可以提供诸如安全、缓存、事务处理等功能。module.xml文件包含了模块的元数据,如模块名称、版本、依赖、激活策略等。通过在services.xml或axis2.xml中引用...

    axiom-api-1.2.10.jar

    Axis2用Axiom处理soap文档和soap信息。 Axiom的一些特性: Lightweight(轻量),更少的内存需要。 Deferred building(延迟构建) Pull based(pull模式),OM基于StAX--标准的pull parser API 。 pull模式 ...

    axiom-api-1.2.6.jar.zip

    - **StAX支持:** Axiom API充分利用StAX的优势,以流式处理XML,降低了内存消耗,提高了处理大型XML文档的速度。 - **XML Infoset模型:** Axiom遵循XML Infoset规范,确保与XML标准的一致性,增强了API的灵活性和...

    axiom-api-1.2.8.jar.zip

    "Axiom API"是一个开放源码的XML处理库,它提供了强大的XML对象模型,使得开发者可以更有效地处理XML文档。"1.2.8"是该库的版本号,表示这是Axiom API的第1.2.8次更新,通常包含了错误修复、性能提升或新功能的添加...

    Axis2 SOAP XML报文节点首字母小写转大写,节点命名空间前缀添加与剔除(JAVA)

    在处理SOAP XML报文时,我们可能遇到一些规范性问题,例如节点首字母大小写的转换,以及节点命名空间前缀的添加与剔除。本文将深入探讨这些问题,并提供相应的解决方案。 首先,关于SOAP XML报文中的节点首字母大小...

    springboot集成axis2-1.7.9实例

    3. **配置Spring Boot**:在Spring Boot的主配置类中,我们需要配置一个Servlet容器来处理Axis2的请求。可以通过扩展`WebApplicationInitializer`接口或使用`@ServletComponentScan`注解来完成。此外,还需要配置...

    axis2.jar包下载

    axis2插件jar包下载。。。。。。。。。。。

Global site tag (gtag.js) - Google Analytics