原始的Apache Axis基于Web服务的第一个Java标准JAX-RPC。 事实证明这不是一个好方法,因为JAX-RPC限制了Axis代码的内部设计,并导致了性能问题和缺乏灵活性。 JAX-RPC还对Web服务开发的方向做出了一些假设,事实证明这是错误的。
到开始Axis2的工作时,已经在开发JAX-RPC的替代产品,因此Axis2的设计足够灵活,可以在基本框架之上实现对替代Web服务标准的支持。 Axis2的最新版本已经实现了对JAXB 2.x Java XML数据绑定标准和替代JAX-RPC的JAX-WS 2.x Java Web服务标准的支持。 本文展示了如何在Axis2中使用JAXB和JAX-WS,并指出了Axis2当前对这些标准的支持的局限性。
Axis2中的JAXB
Axis2实现对JAXB 2.x的支持,这是在使用WSDL2Java从Web服务描述语言(WSDL)服务定义生成代码时可以选择的数据绑定替代方法之一。 (有关其他主要替代方法的讨论,请参见“ Java Web服务:Axis2数据绑定 ”。)与其他大多数替代方法一样,使用JAXB 2.x从WSDL生成代码将创建一组链接类和一组数据。模型类。 链接类(包括客户端存根和服务器端消息接收器)在您的应用程序代码和Axis2之间建立接口。 数据模型类代表实际的消息数据。
JAXB 2.x在数据模型类中使用批注来控制如何将数据转换为XML和从XML转换数据。 注释方法允许您在运行时使用不同的JAXB实现,而无需更改源代码或重新编译类。 JAXB实现要从数据模型类访问批注信息,并在与XML进行相互转换时应用这些批注。
代码下载(请参阅下载 )提供了一个示例应用程序,以演示jaxb目录中Axis2中的JAXB用法。 此应用程序是本系列先前文章中使用的简单库管理服务的另一个版本(包括“ Axis2 Data Binding ”中的数据绑定比较)。 WSDL服务定义定义了四个操作:
-
getBook
检索由国际标准书号(ISBN)标识的特定书的详细信息 -
getBooksByType
检索特定类型的所有书籍的详细信息 -
getTypes
查找可用书籍的类型 -
addBook
将新书添加到库中
清单1显示了经过严格编辑的WSDL版本,其中仅包括与getBook
操作相关的部分:
清单1.库服务WSDL
<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"
schemaLocation="types.xsd"/>
<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>
</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"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
<wsdl:service name="jaxb-library">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/axis2/services/jaxb-library"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Axis2的JAXB支持应该扩展到生成未包装的操作方法(为了方便编程,将消息中包装的值转换为方法参数-再次参见“ Java Web服务:Axis2数据绑定 ”,以获取有关包装和未包装接口的讨论) 。 但是,在当前的Axis2代码或最近的几个发行版中,使用WSDL2Java工具的展开支持在此示例中均不起作用。 至少到目前为止,包装操作方法是将JAXB与Axis2代码生成结合使用的唯一方法(但另请参见JAX-WS讨论 )。 通过包装操作接口,每种服务方法都采用与操作输入消息匹配的单个对象参数,并返回与操作输出消息匹配的对象。
提供的代码提供了服务和测试客户端的实际实现,并设置为与通过运行WSDL2Java生成的类一起使用。 与本系列前几篇文章的示例代码一样,下载内容包括用于使用Apache Ant(在jaxb目录中)构建示例的build.properties和build.xml文件。 首先,您需要编辑build.properties文件以设置Axis2安装的路径(并根据需要更改其他设置)。 然后,您可以在打开到jaxb目录的控制台上键入ant
来运行WSDL2Java,编译提供的代码和生成的代码,并构建用于服务器部署的AAR文件。 要进行尝试,请首先将生成的AAR文件部署到Axis2服务器安装中,然后在控制台上键入ant run
。
客户端JAXB用法
测试客户端使用作为命令行参数传入的服务端点参数创建服务存根的实例,然后执行五个服务调用的序列:
- 获取一本书的信息。
- 获取图书馆中的书籍类型。
- 将一本书添加到库中(如果该书已经存在,则将失败,这将在客户端多次运行而无需重新启动服务器时发生)。
- 如果最后一步成功,请尝试添加具有相同ISBN的另一本书(应该总是失败)。
- 获取有关特定类型的所有书籍的信息。
清单2显示了完整的测试客户端代码。 您可以在每个操作使用的包装对象中看到服务接口的包装性质,例如GetTypes
getTypes
操作所需的getTypes
对象(即使此操作没有输入数据)和由以下GetTypesResponse
返回的GetTypesResponse
对象电话。
清单2. JAXB测试客户端代码
public class WebServiceClient
{
public static void main(String[] args) throws Exception {
// check for required command line parameters
if (args.length < 3) {
System.out.println("Usage:\n java " +
"com.sosnoski.ws.library.jaxb.WebServiceClient host port path");
System.exit(1);
}
// create the client stub
String target = "http://" + args[0] + ":" + args[1] + args[2];
System.out.println("Connecting to " + target);
JaxbLibraryStub stub = new JaxbLibraryStub(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());
List<TypeInformation> types = gtr.getGetTypesReturn();
System.out.println("Retrieved " + types.size() + " types:");
for (int i = 0; i < types.size(); i++) {
TypeInformation type = types.get(i);
System.out.println(" '" + type.getName() + "' with " +
type.getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
AddBook ab = new AddBook();
ab.setType("scifi");
ab.setIsbn(isbn);
ab.getAuthor().add("Cook, Glen");
ab.setTitle(title);
stub.addBook(ab);
System.out.println("Added '" + title + '\'');
title = "This Should Not Work";
ab.setTitle(title);
stub.addBook(ab);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFault e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultMessage().getBook().getTitle() + '\'');
}
// get all books of a type
GetBooksByType gbbt = new GetBooksByType();
gbbt.setType("scifi");
GetBooksByTypeResponse gbbtr = stub.getBooksByType(gbbt);
List<BookInformation> books = gbbtr.getGetBooksByTypeReturn();
System.out.println("Retrieved " + books.size() + " books of type 'scifi':");
for (int i = 0; i < books.size(); i++) {
System.out.println(" '" + books.get(i).getTitle() + '\'');
}
}
}
如果将清单2与“ Java Web Services:Axis2数据绑定 ”中的客户端代码示例进行比较,您会发现它与JiBX和Axis Data Binding(ADB)包装的示例非常相似,主要区别在于JAXB包装器类使用Java 5类型列表而不是数组(JiBX数据绑定也支持此替代方法,但ADB不支持)。
服务器端使用
库服务的服务器端代码由一对类组成,一个类实际实现库处理,另一个类适应Axis2期望的服务接口。 实际的实现代码在不同的数据绑定之间几乎是相同的,仅对生成的应用程序数据模型表示形式进行了少量更改。 清单3显示了更有趣的service-interface类。 与在客户端上一样,包装的接口要求应用程序代码从接收到的包装对象中提取数据并构造要发送的包装对象。
清单3. JAXB服务器代码
public class JaxbLibraryImpl extends JaxbLibrarySkeleton
{
private final BookServer m_server;
public JaxbLibraryImpl() {
m_server = new BookServer();
}
public AddBookResponse addBook(AddBook req) throws AddDuplicateFault {
BookInformation prior = m_server.getBook(req.getIsbn());
if (prior == null) {
BookInformation book = new BookInformation();
book.getAuthor().addAll(req.getAuthor());
book.setIsbn(req.getIsbn());
book.setTitle(req.getTitle());
book.setType(req.getType());
AddBookResponse rsp = new AddBookResponse();
rsp.setAddBookReturn(m_server.addBook(book));
return rsp;
} else {
AddDuplicateFault e =
new AddDuplicateFault("Book already present with matching ISBN");
AddDuplicate ad = new AddDuplicate();
ad.setBook(prior);
e.setFaultMessage(ad);
throw e;
}
}
public GetBookResponse getBook(GetBook req) {
BookInformation book = m_server.getBook(req.getIsbn());
GetBookResponse rsp = new GetBookResponse();
rsp.setGetBookReturn(book);
return rsp;
}
public GetBooksByTypeResponse getBooksByType(GetBooksByType req) {
GetBooksByTypeResponse rsp = new GetBooksByTypeResponse();
rsp.getGetBooksByTypeReturn().addAll(m_server.getBooksByType(req.getType()));
return rsp;
}
public GetTypesResponse getTypes(GetTypes req) {
GetTypesResponse rsp = new GetTypesResponse();
rsp.getGetTypesReturn().addAll(m_server.getTypes());
return rsp;
}
}
“ Java Web Services:Axis2数据绑定 ”没有显示本文中不同数据绑定的服务器接口代码,但是如果将清单3与该文章中的实际代码下载进行比较,您会发现它与ADB和JiBX包装的样本,再次不同之处仅在于使用Java 5类型列表而不是数组。
JAXB数据模型类
清单4显示了通过运行WSDL2Java生成的一些JAXB数据模型类(删除了大多数生成的注释,除了几个作为代表性示例)。 客户端和服务器生成的数据模型类相同,即使它们是由项目构建单独生成的也是如此。 所显示的类是清单2客户端代码和清单3服务器代码中用于getBook
调用的类。 每个类定义和大多数字段定义上的注释(以粗体显示)提供了JAXB用于控制对象与XML之间的转换的配置信息。
清单4. JAXB数据模型类
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"isbn"
})
@XmlRootElement(name = "getBook")
public class GetBook {
@XmlElement(required = true)
protected String isbn;
/**
* Gets the value of the isbn property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getIsbn() {
return isbn;
}
/**
* Sets the value of the isbn property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setIsbn(String value) {
this.isbn = value;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BookInformation", propOrder = {
"author",
"title"
})
public class BookInformation {
protected List<String> author;
@XmlElement(required = true)
protected String title;
@XmlAttribute(required = true)
protected String type;
@XmlAttribute(required = true)
protected String isbn;
public List<String> getAuthor() {
if (author == null) {
author = new ArrayList<String>();
}
return this.author;
}
public String getTitle() {
return title;
}
public void setTitle(String value) {
this.title = value;
}
public String getType() {
return type;
}
public void setType(String value) {
this.type = value;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String value) {
this.isbn = value;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"getBookReturn"
})
@XmlRootElement(name = "getBookResponse")
public class GetBookResponse {
protected BookInformation getBookReturn;
public BookInformation getGetBookReturn() {
return getBookReturn;
}
public void setGetBookReturn(BookInformation value) {
this.getBookReturn = value;
}
}
@XmlAccessorType
批注用于程序包或类级别,以控制如何从类中访问值-作为所有字段,具有get / set访问方法的所有属性,仅作为公共字段和属性,或者仅当由个人指定时注解。 @XmlType
批注用于与模式类型匹配的类或枚举定义,以告知JAXB模式类型的名称和名称空间(如果有),类型表示形式中的值的顺序以及可选的如何构造类实例的方法使用工厂方法。 @XmlRootElement
批注用于与全局元素定义匹配的类或枚举定义,以提供全局元素的名称和名称空间。 @XmlElement
和@XmlAttribute
批注用于值(作为字段或JavaBean属性方法),以提供元素或属性名称和其他特征。
JAXB使用的所有注释都在javax.xml.bind.annotation
包中,包括许多其他注释,但此简单示例所生成的代码中没有使用这些注释。 在这种情况下,JAXB支持从模式生成代码以及从代码开始。 仅当从代码开始时才使用某些注释和选项(例如与对象工厂和序列化器/解串器方法相关的注释和选项)。
Axis2中的JAXB问题
WSDL2Java调用JAXB参考实现中包含的XJC绑定编译器以生成数据模型代码,因此,在大多数方面,数据模型代码的生成独立于Axis2。 如果直接在Web服务使用的架构上运行JAXB XJC绑定编译器,则将生成相同的数据模型。 不幸的是,WSDL2Java和XJC之间的阻抗匹配并不总是完美的,这会导致一些问题。
一个问题与如何在WSDL文档中构建模式有关。 用于库服务的WSDL的原始形式使用了一个文档,该文档包含两个单独的模式,一个用于WSDL消息元素,一个用于应用程序数据(书籍和类型信息)。 WSDL允许,消息元素模式刚刚通过名称空间引用导入了应用程序数据模式。 带有嵌入式模式的WSDL与使用ADB或JiBX数据绑定的WSDL2Java配合良好,但是对于JAXB,它导致在模式的处理期间引发异常。 将应用程序数据模式分离到单独的文件中,并在模式导入中指定文件名,WSDL2Java可以使用JAXB绑定正确处理模式。
另一个问题是XJC提供了许多代码生成选项,以及广泛的自定义项来控制特定模式组件的代码生成细节-但是WSDL2Java没有提供任何将这些选项或自定义项传递给XJC的方法,因此代码生成始终使用默认设置运行。 如果需要使用任何代码生成选项或自定义项,则可能需要与WSDL2Java分开运行XJC。 不幸的是,在WSDL2Java代码生成中无法使用单独生成的JAXB数据模型。 如果需要使用定制的JAXB数据模型,最好的方法可能是运行WSDL2Java来生成自己的JAXB数据模型,然后替换为单独生成的数据模型类,并根据需要手动修改代码以将所有内容修补在一起。 另外,您可以使用下一部分中所述的JAX-WS,它使您可以完全跳过WSDL2Java,但有一些主要限制。
在Axis2中使用JAX-WS
尽管JAXB可以用作Axis2的另一种替代数据绑定技术,但与JAX-WS的区别要深得多。 JAX-WS是定义Web服务的完全不同的方法,它完全替代了标准的Axis2服务器端和客户端配置。 您生成使用wsimport工具,包括在JAX-WS参考实现从WSDL JAX-WS代码(必须单独从Axis2的下载;看到相关信息 ),而不是WSDL2Java的。 甚至部署机制也与Axis2通常使用的AAR文件方法不同。
该代码下载提供了与先前使用的相同示例应用程序的第二个版本,对该版本进行了修改以演示Axis2中的JAX-WS用法。 其代码位于下载的jaxws目录中,并且具有自己的WSDL,build.properties和build.xml。 此JAX-WS版本的WSDL与用于JAXB的WSDL本质上相同,如清单1所示。 WSDL的主要区别在于它为应用程序数据使用了嵌入式模式,而对于使用JAXB数据绑定的WSDL2Java则无效。
使用JAX-WS的WsImport工具从WSDL生成代码时,您将获得与使用WSDL2Java生成JAXB代码时相同的JAXB数据模型和包装器类。 区别在于链接代码,对于JAX-WS,它由一个生成的服务接口和一个客户端服务生成器类组成。 清单5中所示的接口类(经过重新格式化,仅保留一个方法注释作为示例),定义了与WSDL中定义的操作匹配的方法。 客户端和服务器代码都使用此接口。 界面中的广泛注释提供了JAX-WS用于将界面与服务相关联以及界面方法与该服务的操作相关的所有必要配置信息。
清单5. JAX-WS生成的服务接口
@WebService(name = "Library", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@XmlSeeAlso({
ObjectFactory.class
})
public interface Library
{
/**
*
* @param isbn
* @return
* returns com.sosnoski.ws.library.jaxws.BookInformation
*/
@WebMethod(action = "urn:getBook")
@WebResult(name = "getBookReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getBook",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBook")
@ResponseWrapper(localName = "getBookResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBookResponse")
public BookInformation getBook(
@WebParam(name = "isbn", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String isbn);
@WebMethod(action = "urn:getBooksByType")
@WebResult(name = "getBooksByTypeReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getBooksByType",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBooksByType")
@ResponseWrapper(localName = "getBooksByTypeResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBooksByTypeResponse")
public List<BookInformation> getBooksByType(
@WebParam(name = "type", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String type);
@WebMethod(action = "urn:getTypes")
@WebResult(name = "getTypesReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getTypes",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetTypes")
@ResponseWrapper(localName = "getTypesResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetTypesResponse")
public List<TypeInformation> getTypes();
@WebMethod(action = "urn:addBook")
@WebResult(name = "addBookReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "addBook",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.AddBook")
@ResponseWrapper(localName = "addBookResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.AddBookResponse")
public boolean addBook(
@WebParam(name = "type", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String type,
@WebParam(name = "isbn", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String isbn,
@WebParam(name = "author",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
List<String> author,
@WebParam(name = "title", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String title)
throws AddDuplicateFault
;
}
WsImport工具将提供的WSDL识别为与“包装”约定匹配,并自动生成未包装的服务接口。 您可以在清单5中看到这种效果,方法是将各个值作为输入参数,并直接返回任何合适的类型,而不是使用包装对象层(尽管包装对象仍在生成,并在场景由JAX-WS运行时提供)。
提供的代码再次给出了服务和测试客户端的实际实现。 尝试一下,你需要编辑所提供的build.properties文件设置路径都Axis2安装和JAX-WS参考实现的安装(参见相关主题 )。 完成此操作后,在打开到jaxws目录的控制台上键入ant
,以从WSDL运行JAX-WS代码生成,编译提供的代码,并构建用于服务器部署的JAR文件。 要运行测试客户端,请将生成的JAR文件复制到Axis2服务器安装的WEB-INF / servicejars目录中,然后在控制台上键入ant run
。
客户端JAX-WS用法
清单6显示了完整的测试客户端代码。 如果将它与清单2进行比较,您将看到未包装的接口和包装的接口之间的区别,其中未包装的接口对程序员更友好。
清单6. JAX-WS测试客户端代码
public class WebServiceClient
{
public static void main(String[] args) throws Exception {
// check for required command line parameters
if (args.length < 3) {
System.out.println("Usage:\n java " +
"com.sosnoski.ws.library.jaxws.WebServiceClient host port path");
System.exit(1);
}
// create the client stub
JaxwsLibrary service = new JaxwsLibrary();
Library stub = service.getLibrary();
// set the actual endpoint address
String target = "http://" + args[0] + ":" + args[1] + args[2];
System.out.println("Connecting to " + target);
BindingProvider provider = (BindingProvider)stub;
provider.getRequestContext().
put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 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
List<TypeInformation> types = stub.getTypes();
System.out.println("Retrieved " + types.size() + " types:");
for (int i = 0; i < types.size(); i++) {
TypeInformation type = types.get(i);
System.out.println(" '" + type.getName() + "' with " +
type.getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
List<String> authors = new ArrayList<String>();
authors.add("Cook, Glen");
stub.addBook("scifi", isbn, authors, title);
System.out.println("Added '" + title + '\'');
title = "This Should Not Work";
stub.addBook("scifi", isbn, authors, title);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFault e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultInfo().getBook().getTitle() + '\'');
}
// get all books of a type
List<BookInformation> books = stub.getBooksByType("scifi");
System.out.println("Retrieved " + books.size() + " books of type 'scifi':");
for (int i = 0; i < books.size(); i++) {
System.out.println(" '" + books.get(i).getTitle() + '\'');
}
}
}
通常,JAX-WS客户端处理期望在运行时能够访问服务WSDL,并且它使用WSDL来初始化服务器链接。 如果您知道目标服务的WSDL在运行时始终可以直接从服务器获得,并且服务器始终位于同一地址,则只需将WSDL URL赋予WsImport并对其进行硬编码到生成的代码中。 对于最严肃的工作,最好使用WSDL的本地副本,然后在运行时覆盖目标服务地址(如果它与WSDL中的地址不同)。 提供的构建文件采用了这种方法, 清单6中以粗体显示的代码部分演示了如何在运行时更改服务地址而无需修改WSDL。
服务器端JAX-WS的用法
清单7显示了服务器端代码的JAX-WS版本。 实现类上的@WebService
注释(以粗体显示)将实现代码与特定的Web服务接口相关联。 通过实现类上的注释,您可以覆盖生成的服务接口中相应注释的设置( 清单5 )。 在这种情况下,注释将设置服务和端口名称,并提供WSDL服务定义的位置(Axis2显然希望该位置相对于类路径的根或绝对URL)。
清单7. JAX-WS服务器代码
@javax.jws.WebService(endpointInterface="com.sosnoski.ws.library.jaxws.Library",
portName="library", targetNamespace="http://ws.sosnoski.com/library/wsdl",
wsdlLocation="com/sosnoski/ws/library/jaxws/library.wsdl", serviceName="JaxwsLibrary")
public class JaxwsLibraryImpl implements Library
{
private final BookServer m_server;
public JaxwsLibraryImpl() {
m_server = new BookServer();
}
public boolean addBook(String type, String isbn, List<String> author, String title)
throws AddDuplicateFault {
BookInformation prior = m_server.getBook(isbn);
if (prior == null) {
BookInformation book = new BookInformation();
book.getAuthor().addAll(author);
book.setIsbn(isbn);
book.setTitle(title);
book.setType(type);
return m_server.addBook(book);
} else {
AddDuplicate ad = new AddDuplicate();
ad.setBook(prior);
AddDuplicateFault e =
new AddDuplicateFault("Book already present with matching ISBN", ad);
throw e;
}
}
public BookInformation getBook(String isbn) {
return m_server.getBook(isbn);
}
public List<BookInformation> getBooksByType(String type) {
return m_server.getBooksByType(type);
}
public List<TypeInformation> getTypes() {
return m_server.getTypes();
}
}
清单7的其余代码只是清单3的(包装)JAXB示例中所示的包装版本。
Axis2中的JAX-WS问题
Axis2在JAX-WS处理的基础方面做得很好,但是确实有一些限制。 最重要的是,当您在Axis2中使用JAX-WS时,缺少对WS-Security或其他Web服务扩展技术的支持(尽管围绕Axis2构建的应用服务器可能会实现其自己的配置和使用WS-Security的方式)。 这对企业应用程序是一个严重的限制,除了没有任何补偿优势以外,除了稍微简单的配置方法外,目前似乎没有太多理由在Axis2中使用JAX-WS。
从Axis2继续前进
在本文中,您已经了解了将AX2与JAXB 2.x和JAX-WS 2.x Java标准结合使用的基本知识。 Axis2中对JAXB的支持有一些局限性,但是至少对于不需要自定义的简单模式,它提供了Axis2支持的其他数据绑定方法的有用替代方法。 对JAX-WS的支持更为有限,目前仅对不需要WS-Security或任何其他增值功能的简单服务有用。
到目前为止,本系列中的文章都集中在Apache Axis2框架上。 JAXB和JAX-WS的涵盖范围为考察也支持这些标准的其他一些开源Java Web服务框架提供了一个很好的起点。 下个月的专栏文章将探讨与Sun开发的Metro Web Services框架以及JAXB和JAX-WS参考实现一起使用。 它还将更深入地研究JAX-WS的用法和功能。
翻译自: https://www.ibm.com/developerworks/java/library/j-jws8/index.html