- 浏览: 422497 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
masuweng:
好好好,有时间了练习下
使用Java混淆工具yguard -
shengshihouzhe:
第一个eg实现的应该是循环栅栏,不是计数器
Java Phaser使用 -
yukaizhao:
推荐一个很全的guava教程 http://outofmemo ...
google guava cache 处理 -
yanqingluo:
谢谢分享,已关注.
BTrace入门及使用实例 -
luoxiaohui_java:
谢谢分享!
这么好的文章,怎么没人回复呢。
ibm was nd websphere 集群
尽管 XML 消息交换是 Web 服务的核心,但大部分 Web 服务应用程序都不会对 XML 的问题进行考虑。相反,这些应用程序希望交换特定于应用程序的业务数据。在这种情况下,XML 仅仅是用于表示业务数据以支持 Web 服务接口的一个格式而已。XML 可很好地满足此用途,因为它提供了独立于平台的表示形式,可供各种工具进行处理。但应用程序最终需要将 XML 转换为其内部数据结构(或反向转换),以便在应用程序内使用此数据。
数据绑定 是指处理 XML 和应用程序数据结构间的这种转换的技术。可以为应用程序编写自定义数据绑定代码,但大部分开发人员发现使用数据绑定框架更为方便,此类框架将以通用的方式 处理此转换工作,适用于各种应用程序。Apache Axis2 Web 服务框架的一个主要优势在于,此框架从最开始就设计为使用各种数据绑定框架。可以选择最适合您的需求的数据绑定方法,并使用此方法来处理 XML 与数据结构间的转换,同时使用 Axis2 框架(及扩展)来处理实际的 Web 服务工作。
本文将通过使用三个受支持的不同数据绑定实现的同一个 Web 服务的示例代码说明如何使用 Axis2 提供的数据绑定灵活性。可以通过其中了解为何可能会优先选择其中某个数据绑定。
在本系列的前一篇文章 中, 我们已经了解了 Axis2 用于 XML 消息绑定的 AXIOM 文档模型。AXIOM 与其他文档模型的不同之处在于,它支持根据需要绑定模型,而不用一次性完成此工作。当使用数据绑定框架在 XML 和应用程序数据结构之间进行转换时,数据绑定 XML 通常只是 AXIOM 文档模型的一个虚拟部件。除非由于某些原因而需要此模型(用于使用 WS-Security 进行加密或签名时),否则就不会扩展为完整文档模型。
为了隔离应用程序,避免直接使 用 AXIOM 的情况,Axis2 支持从 Web 服务描述语言(Web Services Description Language,WSDL)服务描述生成链接代码。所生成的链接代码使用所选数据绑定框架处理数据结构与 XML 之间的转换细节,让您的应用程序直接访问数据结构。Axis2 还从另一方面提供了有一定限制的支持,从现有代码生成 WSDL。
Axis2 可为服务客户机和服务提供者生成链接代码。客户机链接代码采用存根类的形式,始终从 Axis2 org.apache.axis2.client.Stub
类进行扩展。提供者(或服务器)链接代码采用服务特定的实现框架的形式提供,并提供实现 org.apache.axis2.engine.MessageReceiver
接口的消息接收器类。客户机和服务器链接代码生成工作都由 WSDL2Java 工具进行处理。接下来,我们将了解实际的链接代码,然后将详细讨论如何使用 WSDL2Java 工具,最后将简单说明如何从现有代码着手进行相关工作。
客
户端存根代码为应用程序代码定义访问方法,以调用服务操作。首先要创建存根类的实例,通常使用缺省构造函数(如果服务端点总是与用于生成存根的
WSDL 中定义的端点相同),或使用接受以字符串形式提供的其他端点引用的构造函数进行此工作。创建了存根的实例后,可以选择使用 org.apache.axis2.client.Stub
基类定义的方法来配置各个功能。然后可以调用服务特定的访问方法来实际调用操作。
清 单 1 给出了一个示例,说明如何使用更改为客户机系统 (localhost) 上的缺省 Tcpmon 端口 8800 的服务端点(其在 WSDL 中的任意设定值)创建存根。Tcpmon 是用于监视 Web 服务交换的一个流行工具,因此在客户机代码中使用此选项通常非常有用。创建了存根实例后,超时值的缺省值将改变(调试提供者代码时也很有用,因为很容易就 会超过标准的 20 秒超时设置),并会调用服务方法。
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library"); stub.getServiceClient().getOptions().setTimeoutInMilliseconds(10000000); Types[] types = stub.getTypes(); |
清单 1 中的代码显示了同步方法调用,其中的客户机线程将阻塞在服务调用内,在调用完成且结果可用之后才会返回。Axis2 还支持使用回调接口进行异步调用。清单 2 显示了经过修改的清单 1 代码,其中使用了一个小小的异步调用(应用程序代码仅仅等待操作完成,而不进行任何有用的工作)。
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library"); TypesCallback cb = new TypesCallback(); stub.startgetTypes(cb); Type[] types; synchronized (cb) { while (!cb.m_done) { try { cb.wait(); } catch (Exception e) {} } types = cb.m_result; if (types == null) { throw cb.m_exception; } } ... private static class TypesCallback extends LibraryCallbackHandler { private boolean m_done; private Types[] m_result; private Exception m_exception; public synchronized void receiveResultgetTypes(Type[] resp) { m_result = resp; m_done = true; notify(); } public synchronized void receiveErrorgetTypes(Exception e) { m_exception = e; m_done = true; notify(); } } |
对于 HTTP 连接(如清单 2 中的情况),响应通常将立即返回到客户机。在将请求同响应分离的传输——如 Java™ Message Service (JMS) 或简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)——上操作时,异步调用最有用,因为在这种情况下,请求发出时间和接收到响应的时间存在很大的延迟。当然,使用 HTTP 访问的服务还可能涉及到大量的处理延迟。对于具有此类延迟的 HTTP 服务,可以使用 WS-Addressing 来支持分离的响应,异步调用非常适合用于处理这些响应。
除了存根类(如果使用异步支持生成的话,还包括回调处理程序类)外,还有为客户机代码生成的接口。接口定义与 WSDL portType
所定义的操作匹配的服务方法。存根实现此接口,并添加一些供内部使用的方法。可以直接使用存根,如清单 1
和清单 2
中所示,还可以使用接口来仅仅使用属于服务定义的方法。无论采用哪种方式,调用服务方法时,存根都将使用所选数据绑定框架处理将请求数据对象转换为 XML,以及将返回的 XML 转换为响应数据对象的工作。
如果希望在客户机上直接使用 XML,则根本不需要使用生成的客户机存根类;可以转而使用 org.apache.axis2.client.ServiceClient
类。这样做意味着需要首先配置服务和操作,然后调用 ServiceClient.createClient()
方法为操作创建 org.apache.axis2.client.OperationClient
。为了方便起见,WSDL2Java 工具(本文稍后讨论)提供了相应的选项,可在即使直接使用 XML 的情况下生成存根类。这种情况下生成的存根与数据绑定示例类似,但其中传递的是 AXIOM 元素而不是数据对象。
Axis2 的服务器端链接代码是作为 Axis2 服务器配置的一部分定义的消息接收器类。此消息接收器必须实现 org.apache.axis2.engine.MessageReceiver
接口。此接口定义单个 void receive(org.apache.axis2.context.MessageContext)
方法。在接收到请求消息时,Axis2 框架将调用此方法,然后由此方法负责处理请求的所有处理工作(包括在合适的情况下生成响应)。
如果直接使用 XML(采用 AXIOM 元素的形式),则可以利用服务器端链接的标准 org.apache.axis2.receivers.RawXML*MessageReceiver
类之一(其中 * 描述服务使用的消息交换类型)。否则,就可以使用生成的消息接收器类,其在基于 Axis2 AXIOM
的接口和使用数据对象的服务代码之间进行适配。此服务代码以框架实现的形式生成,其中包含直接引发异常的服务方法。您需要向框架添加自己的代码,以完成服
务器端挂钩。
清单 3 显示了服务端框架的示例(为了便于阅读,进行了格式调整),其中的 getBook()
方法保持生成时的原样,getTypes()
方法通过委托到实际实现类进行实现。
public class LibrarySkeleton { private final LibraryServer m_server; public LibrarySkeleton() { m_server = new LibraryServer(); } /** * Auto generated method signature * * @param isbn * @return book value */ public com.sosnoski.ws.library.Book getBook(java.lang.String isbn) { //Todo fill this with the necessary business logic throw new java.lang.UnsupportedOperationException("Please implement " + this.getClass().getName() + "#getBook"); } /** * Get the types of books included in library. * * @return types */ public com.sosnoski.ws.library.Type[] getTypes() { return m_server.getTypes(); } } |
直接向此类添加代码的缺点在于,如果 服务器接口更改,则需要重新生成此类并包含更改。可以通过添加扩展生成的框架的独立实现类来避免这种情况,从而能在不更改生成的代码的情况下重写框架方 法。为此,需要对生成的 services.xml 服务描述进行更改。所需的工作很简单,直接使用实现类名称替换框架类名称即可。本文稍后将讨论的数据绑定示例全部使用独立的实现类方法。可以在下载 部分获得这些示例 Ant build.xml 文件,以了解如何自动进行替换。
|
|
Axis2 提供了一系列工具来帮助开发人员使用此框架。其中最重要的是允许从 WSDL 服务定义生成 Java 链接代码(在下面讨论)的工具和从现有 Java 代码生成 WSDL 服务定义的工具。
Axis2 提供了 WSDL2Java 工具,用于从 WSDL 服务定义生成代码。可以通过将 org.apache.axis2.wsdl.WSDL2Java
类作为 Java 应用程序运行来直接使用此工具,也可以通过 Ant 任务、Maven 插件或 Eclipse 或 IDEA
插件。拥有这么多选择的缺点在于,从功能和错误修补方面而言,备选方案通常滞后于基本 Java 应用程序,因此通常可能最好直接运行 Java
应用程序(本文将对此进行讨论)。
WSDL2Java 提供很多不同的命令行选项,而且选项的数量还会随着时间的增加而增加。Axis2 文档包括了选项的完整参考,这里将仅仅讨论一些最为重要的内容:
-
-o path
— 设置用于输出类和文件的目标目录(缺省输出到工作目录) -
-p package-name
— 设置生成的类的目标包(缺省为从 WSDL 命名空间生成) -
-d name
— 设置数据绑定框架(adb 表示 ADB,xmlbeans 表示 XMLBeans,jibx 表示 JiBX 以及 none 表示无数据绑定;adb 为缺省选项) -
-uw
— 取消 doc/lit-wrapped 消息的包装,仅适用于受支持的框架(目前包括 ADB 和 JiBX) -
-s
— 仅生成同步客户机接口 -
-ss
— 生成服务器端代码 -
-sd
— 生成服务器端部署文件 -
-uri path
— 为要生成的服务设置指向 WSDL 的路径
还有一些专门针对特定数据绑定框架的 WSDL2Java 选项。稍后讨论数据绑定示例时会看到几个此类选项。
Axis2 还提供了 Java2WSDL 工具,可用于从现有服务代码生成 WSDL 服务定义。不过,此工具有很多限制,包括无法使用 Java 集合类以及在从 Java 类生成的 XML 的结构处理方面不灵活。造成这些限制的部分原因是,由于 Web 服务开发方式的改变,使得大家对此领域没有太多的兴趣。
总的说来,Web 服务和 SOA 领域的很多权威都对从现有代码生成 Web 服务不屑一顾。他们感觉从代码着手会增加 XML 消息结构与特定实现间的偶合,而 Web 服务的总体原则是 XML 应该独立于实现。对此当然有很多支持的声音,但也有人表示反对。其中一个原因涉及到从头编写 WSDL 服务和 XML 模式定义的困难性。WSDL 和模式都是复杂的标准,用于处理这些定义的可用工具都要求对标准足够了解,才能够有效地加以使用。如果开发人员在不以标准为基础的情况进行此工作,所得到 的 WSDL 和模式经常比从代码生成的更为凌乱。另一个问题非常现实。开发人员通常拥有实现某个功能的现有代码,需要将其作为 Web 服务公开,而他们希望能够在不用进行大量更改的情况下使用现有代码。因此从代码生成 WSDL 在可预知的未来一段时间内将仍然可能是个需要考虑的问题。
如果希望使用更为强大的工具代替 Java2WSDL,可以尝试我开发的 Jibx2Wsdl(有关更多信息,请参见参考资料 )。 Jibx2Wsdl 可从提供的一个或多个服务类生成完整的 WSDL 绑定、模式绑定和 JiBX 绑定定义。它支持 Java 5 枚举和通用集合,并同时保留了与旧版本 Java 虚拟机(Java Virtual Machine,JVM)的兼容性,可自动从 Java 源文件将 Javadoc 作为生成的 WSDL 和模式定义的文档导出。Jibx2Wsdl 还提供了广泛的自定义机制来控制服务和 XML 表示形式从 Java 类派生的方式,其中甚至允许将 Java 5 之前的集合与类型化数据一起使用。尽管 Jibx2Wsdl 专门设计为通过 JiBX 数据绑定框架(也是我创建的)简化将现有类作为 Web 服务部署的工作,但生成的 WSDL 和模式都是独立于数据绑定的。可以将其与其他 Java 数据绑定框架甚至其他平台一起使用——生成所需的一切对象,然后去掉 JiBX 绑定并保留其他部分即可。
如 果您使用 Java 5 或更高版本,则另一个备选方案是使用 Java Architecture for XML Binding (JAXB) 2.0 和 Java API for XML Web Services (JAX-WS) Annotation 来将数据对象和服务类作为 Web 服务公开。这些 Annotation 并不提供与 Jibx2Wsdl 相同级别的自定义,但其允许直接在源代码中嵌入配置信息,有些开发人员很喜欢这样做。Axis2 的 1.2 版为 JAXB 2.0 和 JAX-WS 提供了试验支持,这而且会在将来的版本中进一步改进。Jibx2Wsdl 以后的版本也可能支持使用 JAXB 2.0 和 JAX-WS Annotation 进行自定义。(本系列后续文章中将更为深入地讨论 JAXB 2.0 和 JAX-WS,请关注关于从代码生成 WSDL 的这个主题。)
|
|
Axis2(对于 1.2 版)完全支持三种数据绑定备选方案,而且目前正在进行添加更多绑定支持的工作。本文将对使用三种完全受支持的数据绑定框架的示例代码进行比较,并讨论每个框架与 Axis2 一起使用的一些优缺点。
清单 4 中所示的示例代码(也包括在下载 部分的示例下载中)用于图书馆服务,该服务维护按主题类型整理的书籍集合。在此服务上定义了多个操作,包括:
-
getBook
-
getTypes
-
addBook
-
getBooksByType
清单 4 提供了此服务的 WSDL 的部分内容,仅仅显示了 getBook
操作中涉及的部分。
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl" xmlns:wns="http://ws.sosnoski.com/library/wsdl" xmlns:tns="http://ws.sosnoski.com/library/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:types> <schema elementFormDefault="qualified" targetNamespace="http://ws.sosnoski.com/library/wsdl" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://ws.sosnoski.com/library/types"/> <element name="getBook"> <complexType> <sequence> <element name="isbn" type="string"/> </sequence> </complexType> </element> <element name="getBookResponse"> <complexType> <sequence> <element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/> </sequence> </complexType> </element> ... </schema> <schema elementFormDefault="qualified" targetNamespace="http://ws.sosnoski.com/library/types" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="BookInformation"> <sequence> <element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/> <element name="title" type="string"/> </sequence> <attribute name="type" use="required" type="string"/> <attribute name="isbn" use="required" type="string"/> </complexType> ... </schema> </wsdl:types> <wsdl:message name="getBookRequest"> <wsdl:part element="wns:getBook" name="parameters"/> </wsdl:message> <wsdl:message name="getBookResponse"> <wsdl:part element="wns:getBookResponse" name="parameters"/> </wsdl:message> ... <wsdl:portType name="Library"> <wsdl:operation name="getBook"> <wsdl:input message="wns:getBookRequest" name="getBookRequest"/> <wsdl:output message="wns:getBookResponse" name="getBookResponse"/> </wsdl:operation> ... </wsdl:portType> <wsdl:binding name="LibrarySoapBinding" type="wns:Library"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getBook"> <wsdlsoap:operation soapAction="urn:getBook"/> <wsdl:input name="getBookRequest"> <wsdlsoap:body use="literal"/> </wsdl:input> <wsdl:output name="getBookResponse"> <wsdlsoap:body use="literal"/>vi </wsdl:output> </wsdl:operation> ... </wsdl:binding> ... </wsdl:definitions> |
实际的服务实现代码非常简单,即采用硬编码书籍清单填充图书馆实例。客户机代码按照以下顺序执行一系列查询:
- 一个
getBook
- 一个
getTypes
- 两个
addBook
,第二个返回尝试添加重复书籍 ID 的 SOAP 错误 - 一个
getBooksByType
示例间的实现细节有所差别,因为每个示例使用适合于其数据绑定的数据对象。除非专门说明,否则所显示的所有代码对 Axis2 1.1.1 和 1.2
都完全一样。Axis2 1.3
版(撰写本文时正在进行开发)要求对代码进行一些小的更改,因为其中与服务错误对应的生成异常类的命令发生了变化。提供了两个版本的代码供下载(请参见下载
部分)。
在本文中,我们将仅讨论客户机代码,不过提供的下载(请参见下载 部分)包括了所有示例的客户机和服务器代码以及 Ant 构建文件。接下来,让我们分析三个数据绑定框架对应的客户机代码,了解每种方法的优缺点。
ADB 是 Axis2 的数据绑定扩展。与其他数据绑定框架不同,ADB 代码仅可用于 Axis2 Web 服务。这个限制是 ADB 的一大局限,但也带来了一些好处。由于 ADB 与 Axis2 进行了集成,因此其代码可针对 Axis2 要求进行优化。这方面的一个例子就是,ADB 构建于位于 Axis2 核心的 AXis 对象模型(AXis Object Model,AXIOM)文档模型(我们已在本系列的前一篇文章 中对此进行了讨论)之上。ADB 还提供了一些目前其他数据绑定框架所没有的增强功能,包括自动附件处理。WSDL2Java 提供了对 ADB 代码生成的全面支持,其中包括生成与 XML 模式组件对应的数据模型类。
ADB 模式支持具有一定的局限。在当前的 Axis2 1.2 版本中,这些局限包括模式功能,如使用 maxOccurs="unbounded"
的组合器、使用 attributeFormDefault="qualified"
的模式定义和其他一些类似的变体。但 Axis2 1.2 ADB 模式支持比 Axis2 1.1 版要好得多,而且此支持 Axis2 框架的每个发布版本将逐步改进,直到支持所有主要模式功能为止。
ADB 代码生成的基本形式是使用直接模型,其中包含与每个操作使用的输入与输出消息对应的独立类。清单 5 显示了使用此基本 ADB 代码生成模式的示例应用程序的客户机代码中最有意义的部分。此客户机代码说明了与 ADB 生成的类的交互,如用作 getBook()
方法调用的参数的 GetBookDocument
和 GetBookDocument.GetBook
类以及用于从此调用获取返回结果的 GetBookResponseDocument
和 BookInformation
类。
// create the client stub AdbLibraryStub stub = new AdbLibraryStub(target); // retrieve a book directly String isbn = "0061020052"; GetBook gb = new GetBook(); gb.setIsbn(isbn); GetBookResponse gbr = stub.getBook(gb); BookInformation book = gbr.getGetBookReturn(); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } // retrieve the list of types defined GetTypesResponse gtr = stub.getTypes(new GetTypes()); TypeInformation[] types = gtr.getGetTypesReturn(); System.out.println("Retrieved " + types.length + " types:"); for (int i = 0; i < types.length; i++) { System.out.println(" '" + types[i].getName() + "' with " + types[i].getCount() + " books"); } // add a new book String title = "The Dragon Never Sleeps"; isbn = "0445203498"; try { AddBook ab = new AddBook(); ab.setType("scifi"); ab.setAuthor(new String[] { "Cook, Glen" }); ab.setIsbn(isbn); ab.setTitle(title); stub.addBook(ab); System.out.println("Added '" + title + '\''); ab.setTitle("This Should Not Work"); stub.addBook(ab); System.out.println("Added duplicate book - should not happen!"); } catch (AddDuplicateFaultException e) { System.out.println("Failed adding '" + title + "' with ISBN '" + isbn + "' - matches existing title '" + e.getFaultMessage().getBook().getTitle() + '\''); } // create a callback instance CallbackHandler cb = new CallbackHandler(); // retrieve all books of a type asynchronously GetBooksByType gbbt = new GetBooksByType(); gbbt.setType("scifi"); stub.startgetBooksByType(gbbt, cb); long start = System.currentTimeMillis(); synchronized (cb) { while (!cb.m_done) { try { cb.wait(100); } catch (Exception e) {} } } System.out.println("Asynchronous operation took " + (System.currentTimeMillis()-start) + " millis"); if (cb.m_response != null) { BookInformation[] books = cb.m_response.getGetBooksByTypeReturn(); ... |
清单 5 使用利用 -u WSDL2Java 选项生成的代码,该代码特定于 ADB。通过使用此选项,将为每个消息和数据模型类生成独立的 Java 源文件;如果未 使用此选项,ADB 代码生成操作会将所有这些类作为生成的存根的静态内部类生成。使用独立的类要方便得多,因此,如果使用 ADB,则应该使用 -u 选项。
代码生成的直接形式会导致为每个操作的输入和输出生成大量的独立类(不会受到 -u 选项的影响,此选项仅仅以不同的方式组织相同的类而已)。这些生成的消息类经常包含极少(对于 GetTypes
类,甚至没有)有用数据,但生成的消息签名需要这些类。幸运的是,还有适用于很多常见服务的备用代码生成形式。
Web 服务经常以方法调用形式基于现有编程 API 开发,在此情况下,将现有 API 嵌入到 Web 服务内的做法将非常方便。这种做法非常简单;为服务定义的操作(如果要深究的话,从技术上是为端口类型定义的)实际上等效于接口定义中的方法调用。唯一的 主要区别在于,服务将输入和输出定义为 XML 消息,而不是调用参数和返回值。因此,为了在 Web 服务定义中嵌入现有 API,您只需要约定如何将调用参数和返回值表示为 XML 消息结构即可。
幸运的是,Microsoft® 早期就确立了此领域的一个约定,为其他人节约了建立自己约定的时间。此约定称为 wrapped document/literal , 是 .NET 在将方法调用作为 Web 服务操作公开时使用的缺省表示形式。实际上,此包装方法规定每个输入消息都是仅包含子元素序列的 XML 元素,而每个输出消息都是具有单个子元素的 XML 元素。除了完全 .NET 互操作性外,Microsoft 实现还有一些其他并不重要的技术细节,但用于图书馆示例(请参见清单 4 中给出的部分代码)的消息并不是为了这些细节而采用此方法。
WSDL2Java 支持在 ADB 代码生成中对此类 wrapped doc/lit 服务进行取消包装操作。当对合适的 WSDL 服务定义使用取消包装操作时,生成的客户机存根(以及服务器代码框架)将更为简单和直接。清单 6 显示了与清单 5
等效的客户机应用程序代码,不过其中向 WSDL2Java 传递了 -uw 参数,以生成取消包装接口。清单 5 中增加的复杂性层次的消息类几乎都从清单 6 中去掉了(除了 GetTypes
类),服务方法直接接受参数和返回值,而不是嵌入在消息类中。实际上,ADB 仍然生成消息类,并在生成的代码中使用这些类,但代码通常会忽略这些类,而直接使用数据。
// create the client stub AdbUnwrapLibraryStub stub = new AdbUnwrapLibraryStub(target); // retrieve a book directly String isbn = "0061020052"; BookInformation book = stub.getBook(isbn); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } // retrieve the list of types defined TypeInformation[] types = stub.getTypes(new GetTypes()); System.out.println("Retrieved " + types.length + " types:"); for (int i = 0; i < types.length; i++) { System.out.println(" '" + types[i].getName() + "' with " + types[i].getCount() + " books"); } // add a new book String title = "The Dragon Never Sleeps"; isbn = "0445203498"; try { stub.addBook("scifi", isbn, new String[] { "Cook, Glen" }, title); System.out.println("Added '" + title + '\''); title = "This Should Not Work"; stub.addBook("xml", isbn, new String[] { "Nobody, Ima" }, title); System.out.println("Added duplicate book - should not happen!"); } catch (AddDuplicateFaultException e) { System.out.println("Failed adding '" + title + "' with ISBN '" + isbn + "' - matches existing title '" + e.getFaultMessage().getBook().getTitle() + '\''); } // create a callback instance BooksByTypeCallback cb = new BooksByTypeCallback(); // retrieve all books of a type asynchronously stub.startgetBooksByType("scifi", cb); long start = System.currentTimeMillis(); synchronized (cb) { while (!cb.m_done) { try { cb.wait(100L); } catch (Exception e) {} } } System.out.println("Asynchronous operation took " + (System.currentTimeMillis()-start) + " millis"); if (cb.m_books != null) { BookInformation[] books = cb.m_books; ... |
|
ADB 取消包装支持的主要问题在于其尚不完全稳定。清单 6 中的代码适合与 Axis2 1.2 一起使用,其中包含了相对于 Axis2 1.1.1 中使用的 ADB 取消包装进行的几项大改进。但 WSDL2Java 工具要求修改与其他示例使用的 WSDL 文档的结构,以便在此示例中使用,即将数据类的内联模式移动到独立的模式文档中。最重要的是,清单 6 中所示的代码并不能全部都正常工作;代码的最后一部分(即使用异步操作的部分)在运行时出现错误,由于生成的 ADB 客户机存根代码中的错误引发了类强制转换异常。
Axis2 1.2 的后续版本发布时,ADB 取消包装问题应该得到了极大的消除。但 ADB 并不是让 Axis2 支持取消包装的唯一数据绑定框架。JiBX 也提供取消包装支持,JiBX 版本从 Axis2 1.1.1 发布以来就稳定了。可以在本文稍后(讨论了 Axsi 2 数据绑定主要选项后)了解 JiBX 客户机代码。
XMLBeans 是包含数据绑定层的通用 XML 处理框架。其源自一个 BEA Systems 项目,后来提交给了 Apache Foundation。XMLBeans 是 Axis2 支持的第一种数据绑定形式,并将继续作为与 Axis2 一起使用的热门选项(特别是使用复杂模式定义时)。
清单 7 显示了示例应用程序的 XMLBeans 客户机代码中最有意义的部分。对于基本(非取消包装)ADB 代码,每个操作的输入和输出都有一个对应的独立类。但 XMLBeans 与 ADB 并不相同,其中具有针对包含输入或输出类的文档添加的类(例如,除了 GetBook
类外,还有 GetBookDocument
)。其直接效果就是在使用 XMLBeans 代替 ADB 时会添加一个对象创建层。Axis2 中没有为 XMLBeans 提供取消包装支持,因此没有办法避免这个添加的对象层。所得到的结果是 XMLBeans 生成的类比其他数据绑定框架的对等项使用更为复杂。
// create the client stub XmlbeansLibraryStub stub = new XmlbeansLibraryStub(target); // retrieve a book directly String isbn = "0061020052"; GetBookDocument gbd = GetBookDocument.Factory.newInstance(); GetBookDocument.GetBook gb = gbd.addNewGetBook(); gb.setIsbn(isbn); gbd.setGetBook(gb); GetBookResponseDocument gbrd = stub.getBook(gbd); BookInformation book = gbrd.getGetBookResponse().getGetBookReturn(); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } // retrieve the list of types defined GetTypesDocument gtd = GetTypesDocument.Factory.newInstance(); gtd.addNewGetTypes(); GetTypesResponseDocument gtrd = stub.getTypes(gtd); TypeInformation[] types = gtrd.getGetTypesResponse().getGetTypesReturnArray(); System.out.println("Retrieved " + types.length + " types:"); for (int i = 0; i < types.length; i++) { System.out.println(" '" + types[i].getName() + "' with " + types[i].getCount() + " books"); } // add a new book String title = "The Dragon Never Sleeps"; isbn = "0445203498"; try { AddBookDocument abd = AddBookDocument.Factory.newInstance(); AddBookDocument.AddBook ab = abd.addNewAddBook(); ab.setAuthorArray(new String[] { "Cook, Glen" }); ab.setIsbn(isbn); ab.setTitle(title); ab.setType("scifi"); stub.addBook(abd); System.out.println("Added '" + title + '\''); title = "This Should Not Work"; ab.setTitle(title); stub.addBook(abd); System.out.println("Added duplicate book - should not happen!"); } catch (AddDuplicateFaultException e) { System.out.println("Failed adding '" + title + "' with ISBN '" + isbn + "' - matches existing title '" + e.getFaultMessage().getAddDuplicate().getBook().getTitle() + '\''); } // create a callback instance BooksByTypeCallback cb = new BooksByTypeCallback(); // retrieve all books of a type asynchronously GetBooksByTypeDocument gbtd = GetBooksByTypeDocument.Factory.newInstance(); gbtd.addNewGetBooksByType().setType("scifi"); stub.startgetBooksByType(gbtd, cb); long start = System.currentTimeMillis(); synchronized (cb) { while (!cb.m_done) { try { cb.wait(100L); } catch (Exception e) {} } } System.out.println("Asynchronous operation took " + (System.currentTimeMillis()-start) + " millis"); if (cb.m_response != null) { BookInformation[] books = cb.m_response.getGetBooksByTypeResponse().getGetBooksByTypeReturnArray(); ... |
|
清单 7 中的客户和对应的服务器代码可在 Axis2 1.1.1 下正常执行,但由于1.2 版中针对 XMLBeans 的错误处理代码生成存在问题,会在添加重复书籍 ID 时遇到意外异常,从而失败。这个问题应该已经在下一个 Axis2 版本中得到解决。
尽
管 XMLBeans 声称 100% 支持 XML 模式,但这个说法的准确性有待商榷。对于几乎任何模式构造,XMLBeans
都生成了一组能用于读写匹配此模式的文档。但与本文讨论的其他数据绑定框架不同的是,XMLBeans
缺省情况下并不进行任何工作来执行模式。例如,如果将清单 7
代码中添加的设置书籍标题的代码行注释掉,XMLBeans 仍然能正常读写缺少所需的 <title> 元素(因而无效)的文档。清单
8 显示了此代码更改,并给出了发送到服务器进行添加请求的 XML 以及检索书籍时从服务器返回的 XML。对于检索响应,XML 文档包括
<title> 元素,但使用了 xsi:nil="true"
属性,这在模式中是不允许的,因此同样也无效。
AddBookDocument abd = AddBookDocument.Factory.newInstance(); AddBookDocument.AddBook ab = abd.addNewAddBook(); ab.addAuthor("Cook, Glen"); ab.setIsbn(isbn); ab.setType("scifi"); // ab.setTitle(title); System.out.println("Validate returned " + abd.validate()); stub.addBook(abd); ... <addBook xmlns="http://ws.sosnoski.com/library/wsdl"> <type>scifi</type> <isbn>0445203498</isbn> <author>Cook, Glen</author> </addBook> <getBooksByTypeResponse xmlns="http://ws.sosnoski.com/library/wsdl"> ... <getBooksByTypeReturn isbn="0445203498" type="scifi"> <author xmlns="http://ws.sosnoski.com/library/types">Cook, Glen</author> <title xmlns="http://ws.sosnoski.com/library/types" xmlns:xsi="http://www.w3.org/2001 /XMLSchema-instance" xsi:nil="true"/> </getBooksByTypeReturn> </getBooksByTypeResponse> |
这是未设置所需值的一个简单示例。对于更 为复杂的模式,XMLBeans 生成的 API 可能会隐藏更多的缺陷。XMLBeans 用户邮件列表的最近一次讨论曾谈及这样的情况,即必须将值添加到两个不同的列表,以更改生成正确输出的顺序。因此 XMLBeans 要求开发人员既要了解模式,还要了解生成的代码如何与模式相关,以确保应用程序代码构建有效的 XML 文档。数据绑定框架的一个主要好处是,通常能够对开发人员隐藏模式的这些细节,而 XMLBeans 显然在这方面做得并不好。
可以通过调用生成类中包括的 validate()
方法来避免 XMLBeans 处理和生成无效 XML 文档的问题。如果使用 XMLBeans,则应至少在测试和开发期间使用此方法来检查所有文档。不过,验证对性能具有很大的影响(正如您在下一篇文章中将看到的,即使不对每个文档调用 validate()
,XMLBeans 也已经非常慢了),因此很多应用程序都应该在生产部署中避免验证开销。就结果信息而言,验证也具有相当的局限性。为了避免导致验证错误,应该对出现错误的文档运行独立的模式验证。
JiBX(我 自己开发的)是主要侧重使用现有 Java 类(而不是从模式进行代码生成)的数据绑定框架。对于 JiBX,要首先创建绑定定义,以定义 Java 数据对象与 XML 之间如何转换,然后使用可通过添加实现转换的方法(作为字节码)来增强数据类文件的工具对该绑定进行编译。JiBX 运行时框架将随后使用这些添加的方法来在数据和 XML 之间进行转换。
JiBX 方法提供了一些独有的优势,也有自己独有的缺点。就好的一面而言,JIBX 可让您在 Web 服务接口添加到现有服务代码的情况下直接使用现有类。Jibx2Wsdl 工具特别适合这种用途,因为它会生成所需的所有内容,从而方便地将现有代码作为 Axis2 服务部署。可以在使用单个数据模型的情况下为相同的类定义不同的绑定,以同时用于文档的不同 XML 版本。通过修改绑定,甚至通常能在重构数据类的情况下保持相同的 XML 表示形式。
清单 9 显示了 JiBX 客户机代码中有意义的部分,其中使用了匹配消息元素的类。此代码与清单 5
中所示的 ADB 对等项类似,因此这里就不详细讨论了。唯一值得注意的差异是,由于数据类和消息类都在用户的控制之下,因此可以方便地向通过 JiBX 使用的类添加常规构造函数(如 AddBookRequest
的情况)和其他支持方法。
// create the server instance JibxLibraryStub stub = new JibxLibraryStub(target); // retrieve a book directly String isbn = "0061020052"; GetBookResponse bresp = stub.getBook(new GetBookRequest(isbn)); Book book = bresp.getBook(); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } isbn = "9999999999"; bresp = stub.getBook(new GetBookRequest(isbn)); book = bresp.getBook(); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } // retrieve the list of types defined GetTypesResponse tresp = stub.getTypes(new GetTypesRequest()); Type[] types = tresp.getTypes(); System.out.println("Retrieved " + types.length + " types:"); for (int i = 0; i < types.length; i++) { System.out.println(" '" + types[i].getName() + "' with " + types[i].getCount() + " books"); } // add a new book String title = "The Dragon Never Sleeps"; isbn = "0445203498"; try { AddBookRequest abr = new AddBookRequest("scifi", isbn, title, new String[] { "Cook, Glen" }); stub.addBook(abr); System.out.println("Added '" + title + '\''); title = "This Should Not Work"; abr = new AddBookRequest("scifi", isbn, title, new String[] { "Nobody, Ima" }); System.out.println("Added duplicate book - should not happen!"); } catch (AddDuplicateFaultException e) { System.out.println("Failed adding '" + title + "' with ISBN '" + isbn + "' - matches existing title '" + e.getFaultMessage().getBook().getTitle() + '\''); } // create a callback instance BooksByTypeCallback cb = new BooksByTypeCallback(); // retrieve all books of a type asynchronously stub.startgetBooksByType(new GetBooksByTypeRequest("scifi"), cb); long start = System.currentTimeMillis(); synchronized (cb) { while (!cb.m_done) { try { cb.wait(100); } catch (Exception e) {} } } System.out.println("Asynchronous operation took " + (System.currentTimeMillis()-start) + " millis"); if (cb.m_response != null) { Book[] books = cb.m_response.getBooks(); |
清单 10 显示了对等的 JiBX 取消包装代码。和 ADB 取消包装代码类似,理解和使用服务调用的取消包装形式比使用直接代码简单得多。JiBX 和 ADB 版本唯一重要的区别在于,对于 JiBX,并不需要在不传递值时创建对象,而 getTypes()
调用的 ADB 版本则要求进行此工作。JiBX 取消包装支持也比 ADB 版本更为稳定一些,因为从 Axis2 1.1.1 起就提供了全面支持。
// create the server instance JibxUnwrapLibraryStub stub = new JibxUnwrapLibraryStub(target); // retrieve a book directly String isbn = "0061020052"; Book book = stub.getBook(isbn); if (book == null) { System.out.println("No book found with ISBN '" + isbn + '\''); } else { System.out.println("Retrieved '" + book.getTitle() + '\''); } // retrieve the list of types defined Type[] types = stub.getTypes(); System.out.println("Retrieved " + types.length + " types:"); for (int i = 0; i < types.length; i++) { System.out.println(" '" + types[i].getName() + "' with " + types[i].getCount() + " books"); } // add a new book String title = "The Dragon Never Sleeps"; isbn = "0445203498"; try { stub.addBook("scifi", isbn, new String[] { "Cook, Glen" }, title); System.out.println("Added '" + title + '\''); title = "This Should Not Work"; stub.addBook("xml", isbn, new String[] { "Nobody, Ima" }, title); System.out.println("Added duplicate book - should not happen!"); } catch (AddDuplicateFaultException e) { System.out.println("Failed adding '" + title + "' with ISBN '" + isbn + "' - matches existing title '" + e.getFaultMessage().getBook().getTitle() + '\''); } // create a callback instance BooksByTypeCallback cb = new BooksByTypeCallback(); // retrieve all books of a type asynchronously stub.startgetBooksByType("scifi", cb); long start = System.currentTimeMillis(); synchronized (cb) { while (!cb.m_done) { try { cb.wait(100L); } catch (Exception e) {} } } System.out.println("Asynchronous operation took " + (System.currentTimeMillis()-start) + " millis"); if (cb.m_books != null) { Book[] books = cb.m_books; |
JiBX 取消包装支持在使用的类方面也与 ADB 有差别。当使用 ADB 取消包装时,所有消息元素的类仍然在后台生成和使用。对于 JiBX,使用直接处理时必须将类定义为与消息元素对应,如清单 9
中所示;对于取消包装处理,只有作为值传递的类需要在绑定定义中加以定义和包括。无论采用哪种方法,JiBX 绑定定义都需要在运行 Axis2 WSDL2Java 工具前创建,而且需要使用 -Ebindingfile
命令行参数传入。
JiBX 绑定方法最大的缺陷(至少从 Web 服务方面可以这样说)可能就是,JiBX 目前对从 XML 模式定义工作的支持非常微弱。不过,即使是 Xsd2Jibx 工具提供的这个微弱支持,也尚未集成到 Axis2 WSDL2Java 代码生成中。这意味着需要在运行 WSDL2Java 生成 Axis2 链接代码前创建 Java 数据类和绑定定义。JiBX 所需的字节码增强步骤在某些环境中也可能出现问题,因为通常需要在应用程序构建时进行此工作,可在类中得到没有源代码可用的代码。
正如前面所提到的,JiBX 数据绑定提供了一些独特的好处。就 Axis2 使用而言,JiBX 也提供了优于其他框架的优势,即支持能够插入到 Axis2 版本中纠正发布之后发现的错误的错误修复程序版本(有关详细信息,请参见参考资料 部 分的“获得相关产品和技术”)。对于其他框架,获取错误修复程序的唯一方式就是迁移到 Axis2 的更高版本,而这样通常会带来其他问题。预计将来 JiBX 将提供稳定的从模式生成代码和绑定的支持。到提供此功能的那一天,就可以将 JiBX 视为 Axis2 的优秀全能数据绑定备选方案了。到那时,使用现有 Java 代码的做法将是最佳的,而 Jibx2Wsdl 工具恰恰在这方面提供了出色的支持。
|
|
Axis2 目前提供对三种不同数据绑定框架的全面支持:
- ADB 专门为 Axis2 设计,仅能用于 Axis2 环境中。对于 Axis2 1.3 版,提供了对从模式生成代码的良好支持(并在不断改进)。另外还支持常规取消包装服务方法和自动附件处理,从而使其成为了从现有 WSDL 服务定义着手时的首要选项。
- XMLBeans 提供对在生成的 Java 代码中建模模式结构的最全面支持。但其会创建给定模式的最为复杂的 Java 模型,并不支持使用取消包装服务方法来实现更为简单的接口。缺省情况下,甚至不会对输入或输出 XML 文档执行基本模式结构规则,从而很可能会创建无效的 XML 文档或接受此类文档进行处理。
- JiBX 是唯一支持使用现有 Java 类的备选方案。另外还提供了对取消包装服务方法出色的支持。但集成到 Axis2 中的 JiBX 支持并不处理从模式生成代码的情况,甚至 JiBX 工具所提供的从模式生成代码的独立支持目前还仅限于模式支持。
Axis2 提供了这些数据绑定框架间的选择,这非常好,因为并没有那一个选项能满足所有需求。将来 Axis2 还将提供对 JAXB 2.0 的全面支持,我将在本系列关于相关 JAX-WS 2.0 的后续文章中对此进行讨论。了解每个框架的优缺点可帮助您根据自己的需求作出最适当的选择,并在投入生产前了解潜在的问题区域。在本系列的下一篇文章中, 我们将了解 Axis2 数据绑定框架比较的另一个方面:性
相关推荐
axis2不同数据绑定方式实例
在Axis2中,有一些关键的jar包,如`axis2-adb.jar`、`axis2-kernel.jar`、`axiom-api.jar`、`axiom-impl.jar`等,它们分别负责处理数据绑定、核心服务、AXIOM(XML对象模型)接口和实现。 - `axis2-adb.jar`: 包含...
1. axis2-adb.jar: Axis2数据绑定(ADB)模块,用于将Java对象序列化为SOAP消息和反序列化回对象。 2. axis2-kernel.jar:Axis2核心模块,包含了处理Web服务请求和响应的基本组件。 3. axis2-transport-...
- axis2-adb.jar:Axis2数据绑定模块,用于处理XML到Java对象的转换。 - axis2-kernel.jar:Axis2的核心模块,包含基本的服务处理逻辑。 - axis2-transport-http.jar:HTTP传输模块,用于处理HTTP请求和响应。 - ...
- `axis2-adb.jar`:Axis2数据绑定(ADB)实现,用于序列化和反序列化SOAP消息。 - `axis2-transport-http.jar`:HTTP传输模块,处理HTTP请求和响应。 - `axis2-kernel.jar`:Axis2的核心组件,包含了服务引擎和...
通过对Axis与Axis2在使用WSDL2Java工具时的不同之处的详细探讨,我们可以看到,虽然两种工具都实现了相似的功能,但Axis2在很多方面都进行了优化和改进,尤其是在命令行参数、部署描述文件生成以及数据绑定等方面。...
Axis2支持更多的数据绑定,包括XMLBeans、JiBX、JaxMe和JaxBRI,以及它原生的数据绑定(ADB)。Apache CXF目前仅支持JAXB和Aegis,默认是JAXB 2.0,但CXF 2.1版本中将支持XMLBeans、JiBX和Castor等数据绑定。 语言...
- JAXB(Java Architecture for XML Binding):Java到XML数据绑定的API,用于将Java对象转换为XML表示,反之亦然。 - MTOM和SwA:用于优化大型二进制数据传输的技术。 - JAX-WS(Java API for XML Web Services):...
`adb`代表“抽象数据绑定”,它是Axis2的一种数据绑定机制,用于将XML消息转换为Java对象。 其次,“service”标签表明我们讨论的是与服务相关的组件。在Axis2中,`axis2-service-builder.jar`是用于生成服务部署...
10. **axis2-adb-1.4.jar**:Axis2 ADB(Automatic Data Binding)模块是Axis2的一种轻量级数据绑定机制,用于简化Web服务的数据交换。 11. **axis2-metadata-1.4.jar**:这个JAR文件包含了Axis2的元数据处理,用于...
在这里,我们提到了"axis2-adb-1.6.2.jar",这是Axis2的抽象数据绑定(Abstract Data Binding)模块,它允许将XML数据自动转换为Java对象和反之亦然。ADB简化了处理复杂数据结构,如List,因为它能自动将XML元素映射...
1. **核心库**:如axis2-adb.jar、axis2-kernel.jar,包含Axis2的核心服务和数据绑定(ADB)机制。 2. **模块库**:如axis2-transport-http.jar、axis2-transport-local.jar,提供HTTP和本地传输支持。 3. **XML...
6. **数据绑定**:Axis2提供了数据绑定框架,如ADB(Axis Data Binding)、JAXB(Java Architecture for XML Binding)和XMLBeans,它们可以自动将XML消息转换为Java对象和反之亦然。 7. **扩展性**:Axis2支持许多...
2. **数据绑定基础** 数据绑定是将应用程序的数据源与UI元素关联的过程,使得数据的改变能够自动反映到界面中。在C#中,我们可以使用各种数据源,如数组、列表、数据库查询结果等,将这些数据绑定到ChartControl。 ...
5. 数据绑定:Axis2支持多种数据绑定框架,如Axiom(Axis2 Object Model)、JAXB、Castor等,用于XML到Java对象和反之的转换。 二、Axis2快速入门 1. 安装与配置:Axis2的安装通常涉及下载发行版,解压后配置环境...
**Axis2接口生成WSDL工具详解** 在Web服务开发领域,Apache Axis2是一个重要的开源工具,它被广泛用于创建和部署SOAP(Simple Object Access Protocol)和RESTful Web服务。标题中的"Axis2接口生成WSDL工具"正是 ...
6. **数据绑定框架**:Axis2支持多种数据绑定框架,如Aegis、 Axis2 Java2WSDL、ADB(Axis Data Binding)、JAXB等,用于将Java类与SOAP消息结构映射,简化开发过程。 7. **安全特性**:Axis2集成了一些安全标准,...
2. **数据绑定**:Axis2与多种数据绑定框架兼容,如ADB(Axis Data Binding)、JAXB(Java Architecture for XML Binding)等,用于自动序列化和反序列化XML数据。 3. **安全**:Axis2支持WS-Security标准,提供消息...
- **数据绑定**:AXIS2支持多种数据绑定框架,如ADB(Axis2 Data Binding)、JAXB(Java Architecture for XML Binding)和XMLBeans,它们可以帮助将XML消息自动转换为Java对象,反之亦然。 - **消息处理**:AXIS2...
1. **axis2-adb.jar**:这个jar包包含了Axis2的数据绑定抽象(ADB)框架,用于将XML数据自动映射到Java对象。ADB提供了一种简单而高效的方式来处理XML消息。 2. **axis2-kernel.jar**:这是Axis2的核心模块,包含了...