本模块讲述在Sun Java System应用服务器7环境下开发、组装、以及部署基于RPC的Web服务的过程;以及如何创建调用此类服务的客户端。
本模块包括了以下几节:
用于基于XML的远程过程调用的Java API是用来创建使用远程过程调用(RPC)的Web服务和客户端的API。RPC机制允许客户端执行位于分布式环境中其他系统上的过程。在JAX-RPC中,一个远程过程调用由基于XML的协议来描述,比如SOAP。SOAP规范定义了封装结构、编码规则、以及描述远程过程调用和响应的约定。这些调用和响应在HTTP上作为SOAP消息被传递。想要了解更多关于SOAP消息的信息,请参见"SOAP消息"。
JAX-RPC采用了HTTP、 SOAP、以及由世界互联网组织(W3C)制定的WSDL技术,该技术使客户端与运行在非Java平台上的web服务之间的相互访问成为可能。Sun ONE应用服务器的JAX-RPC API实现采用了HTTP作为传输协议。这个实现还为生成stub、tie、以及其他客户端和服务器端需要的部件提供了必要工具。请参见"JAX-RPC工具"。
Sun Java System应用服务器的JAX-RPC实现为开发人员带来了如下益处:
JAX-RPC Web服务是同步的服务,就是说,每当客户端调用一个JAX-RPC Web 服务操作的时候,它总会接收到一个SOAP响应,即使实现操作的方法返回的是空值。关于Web服务操作的更多信息,请参见"Web 服务中使用的消息模型。"。
部署在Sun Java System应用服务器上的Web服务可以被任何类型的客户端访问,比如任何充当客户端角色的J2EE组件,任何基于J2SE的客户端,或者.net客户端。
以下步骤讲述了利用Java接口及其实现创建JAX-RPC Web服务的过程:
1. 定义一个代表服务远程接口的类,即服务的终端接口。该类包含了可能被客户端调用的服务方法的声明。服务终端接口扩展了java.rmi.Remote接口,而且它的方法必须抛出java.rmi.RemoteException。下面的代码演示了服务终端接口的创建。
package hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloIF extends Remote{
public String sayHello(String S) throws RemoteException;
}
在上面的代码示例中,程序包文件的名称是hello,服务定义接口是HelloIF.java。
服务接口部署在实现了JAX-RPC运行时系统的容器中。
2. 编写服务实现类。服务实现类是一个普通的java类。调用在servlet容器中进行。下面的代码示例演示了如何编写服务实现类。
package hello;
public class HelloImpl implements HelloIF {
public String message = "Hello";
public String sayHello(String S) {
return message + S;
}
}
3. 为了处理客户端和服务终端之间的通讯,JAX-RPC在客户端和服务器端需要多个类、接口、和其他文件。Sun ONE应用服务器中的JAX-RPC实现提供了wscompile工具来生成这些部件。
Wscompile工具使用配置文件config.xml为生成客户端和服务器端部件读取接口和实现类。Wscompile工具还为服务创建了WSDL描述。
例子的配置文件如下:
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
typeNameSpace="http://hello.org/hello/type"
packageName="hello">
关于配置文件的信息,请参见"配置文件"。
关于用于创建配置文件的XML schema的信息,请参见"XML Schema定义"。
下面是运行wscompile工具的语法:
wscompile -gen:both -d build/client -classpath build/shared config.xml
Stub和tie是wscompile工具生成的最重要的部件。Stubs和tie是使服务终端和客户端能够进行通讯的类。Stub类位于客户端,处在服务终端和JAX-RPC客户端运行时系统之间。Stub类负责把JAX-RPC服务客户端请求转换成SOAP消息并且利用特定的协议发送到服务终端。它也把按照SOAP消息格式接收到的服务终端响应转换成客户端需要的格式。转换客户端请求到SOAP格式称为编组,把SOAP格式反过来转换成客户端响应称为反编组。
类似地,tie类位于服务器端,处在服务终端和JAX-RPC运行时系统之间。Tie类处理数据在服务终端类和SOAP格式之间的编组和反编组。Stub是为服务终端充当代理的本地对象。
可以使用一个ant编译文件(build.xml)来编译服务,生成服务器端部件并创建可移植的war文件。可在以下位置找到一个示例build.xml文件。
install_dir/samples/webservices/jaxrpc/simple/src
关于创建build.xml文件的更多信息,请看"创建 build.xml 文件"。
4. 组装并且部署服务到Sun Java System应用服务器。请参见"组装并部署JAX-RPC Web服务".。
5. 编写调用服务的客户端应用程序。请参见"调用JAX-RPC Web服务".
使用WSDL的JAX-RPC Web服务
可以使用已有的WSDL文件创建JAX-RPC Web服务。在该方法中,wscompile工具利用WSDL生成服务定义接口。WSDL端口类型被映射为Java服务定义接口。要从WSDL生成服务接口,可以使用-import选项来执行wscompile工具,并以WSDL文件的存放位置作为参数。或者,你可你在名为config.xml的配置文件中存储生成服务定义接口所必需的信息。config.xml中一般存储了项要访问的WSDL所在的位置。
下面的wscompile命令读取config.xml,从而生成服务定义接口:
wscompile -gen:server -import
包含了WSDL文件的配置文件具备以下格式:
包含了WSDL文件的配置文件具备以下属性:
关于用于建立配置文件的XML schema的信息,请参见"XML Schema定义"。
下面的代码是一个示例配置文件,位于:install_dir/samples/webservices/jaxrpc/simple
packageName="samples.webservices.jaxrpc.simple"/>
生成服务接口之后,请执行"开发JAX-RPC Web服务".这一节中的步骤2到步骤5。
JAX-RPC Web服务应用程序能够被组装并且作为一个WAR文件部署到Sun Java System应用服务器上。WAR文件包括了压缩格式下web应用程序所需的文件。
以下步骤讲述了组装和部署Web服务应用程序到Sun Java System应用服务器的过程。
1. 创建WAR文件。为了创建一个包含服务代码的WAR文件,请创建一个build.xml文件,并为目标名称指定create-war命令。以下代码是一个创建WAR文件的示例build.xml文件。
description="Packages the WAR file">
当被执行时,这个XML文件把文件打包成一个名为hello-portable.war的WAR文件。这个WAR文件还不能被部署,因为没有包含tie类。WAR(web 应用存档)文件包括了压缩格式下完整的web应用程序。
文件根目录下的一个特定目录WEB-INF中包含了与不在应用程序公共文件树上的应用程序相关的一切。没有任何一个WEB-INF中的文件能够直接服务于客户端。WEB-INF的内容包括:
Web应用程序目录结构符合J2EE规范中描述的结构。
在本例中,hello-portable.war包含以下文件:
2.定义指定服务名称及其服务终端接口和类的配置文件。配置文件的名称必须是jaxrpc-ri.xml。下面是本例子的配置文件:
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd"
version="1.0"
targetNamespaceBase="http://hello.org/wsdl"
typeNamespaceBase="http://hello.org/types"
urlPatternBase="/ws">
name="HelloWorld"
displayName="HelloWorld Service"
description="A simple web service"
interface="samples.webservices.jaxrpc.simple.HelloIF"
implementation="samples.webservices.jaxrpc.simple. HelloImpl"/>
endpointName="HelloWorld"
urlPattern="/simple"/>
配置文件包含了以下web服务属性:
关于用于创建运行时配置文件的XML schema的信息,请参见"XML Schema定义".
3. 创建web.xml配置描述文件,其中包含了部署服务所需的信息,例如服务到URL的映射、指定WAR文件中配置文件的位置等等。
想要了解关于配置描述文件的更多信息,请参见Sun Java System应用服务器开发人员指南。
关于DTD文件以及XML的基本信息,请参考XML规范,位于:
http://www.w3.org/TR/REC-xml
下面是本例的配置描述文件:
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
关于用于创建运行时配置文件的XML schema的信息,请参见"XML Schema定义".
Web服务应用程序拥有一个目录结构,通过到应用程序文件根目录的映射 (例如, /hello),整个结构都能够被访问。
4. 使用wsdeploy工具创建可部署的WAR模块。Wsdeploy工具执行wscompile工具来生成stub、tie类、以及其他必要的类。
wsdeploy -keep tmpdir tempdir -o hello.war hello-portable.war
当wsdeploy命令被执行时,完成了以下任务:
关于使用wsdeploy命令行工具的信息,请参见"wsdeploy工具",
5. 使用asadmin部署命令部署WAR模块。
例如,
asadmin> deploy --user admin --password admin --host localhost --port 4848 --type web --instance server1 /sun/appserver7/samples/webservices/jaxrpc/simple/Hello.war
关于使用asadmin命令行工具的更多信息,请参见Sun Java System应用服务器开发人员指南。
调用web服务本质上是指客户端应用程序访问web服务这种行为。部署在Sun ONE应用服务器的web服务能够被任何客户端访问。就是说,应用服务器中的任何J2EE组件都能够担当客户端的角色。任何应用程序或者应用客户端都能够访问web服务。客户端可以使用Apache SOAP 库调用Web服务,或者客户端可以是一个.net客户端。
本节讲述了开发能够调用部署在Sun Java System 应用服务器上的JAX-RPC web服务的JAX-RPC客户端的过程。
JAX-RPC客户端是为了能在在运行时调用web服务而使用JAX-RPC API的应用程序。这些客户端利用WSDL导入服务,并且可以调用在非java平台上定义并部署的服务。为了从客户端的视角建模Web服,JAX-RPC定义了javax.xml.rpc.Service接口。你可以使用J2SE或者J2EE客户端编程模型开发JAX-RPC客户端。
调用web服务的主要步骤如下。
1. 添加客户端JAR文件到客户端jar路径。关于如何添加jar文件到类路径的详细信息,请参见"配置客户端环境 "。
2. 创建基于java的服务客户端。
3. 组装并部署客户端应用程序,请参见"组装并部署JAX-RPC客户端".
4. 执行Java客户端来调用web服务。
你可以使用stub方法、动态代理、或是调用接口这几种方法来创建JAX-RPC客户端。本节将会讨论以下主题:
i. 使用动态代理创建客户端
ii. 用调用接口创建客户端
通过生成stub方法创建客户端
当JAX-RPC客户端知道调用什么方法并且知道如何调用,比如传递什么参数的时候,可以使用stub。通过stub调用一个远程方法就好比通过Java远程方法调用(RMI)系统调用方法。Stub使调用远程方法看起来就象调用本地方法,从而简化了远程方法的调用。本地的stub对象用来代表远程对象。为了进行远程方法调用,JAX-RPC客户端向本地stub进行方法调用。
Stub类是描述web服务的WSDL端口的映射。因此它必须实现反映相关端口类型方法的服务定义接口。这样,客户端就具备了对web服务终端类型明确的,早绑定的访问能力。
Stub还必须实现javax.xml.rpc.Stub接口,该接口为客户端动态配置stub提供了便利。
典型情况下,JAX-RPC客户端执行以下步骤。这些步骤展示在图"JAX-RPC 客户端模型"中。
1.客户端调用stub。
2.Stub重定向调用到合适的web服务。
3.服务器捕获该调用并把它重定向到框架。
4.框架包装服务的真正实现,然后代表客户端调用web服务。
5.框架返回调用给服务器
6.接着,Web服务返回信息给原来的客户端stub。
7.最后,客户端stub返回信息给客户端应用程序。
JAX-RPC客户端模型
下面这一节讲述了这些步骤:
生成stub
可以使用wscompile工具为客户端生成stub。除了生成stub,wscompile工具还为服务器生成tie。为了生成stub,请设置PATH到install_dir/share/bin目录。使用下面的语法运行该工具:
wscompile -gen:client -d build/client -classpath build/shared config.xml
关于wscompile工具的更多信息,请参见"wscompile工具"。
有两种方法可以生成stub。可以从服务终端定义或是WSDL文件生成stub。上面的Wscompile命令采用了服务终端定义来生成stub。
编写客户端代码
确定在类路径中添加了必要的jar文件。想要了解更多,请参见"配置客户端环境 "。
客户端执行了以下步骤:
1.获得接口stub的一个实例
2.设定stub的终端属性,从而指定web服务的服务终端。
3.调用方法。
本例使用服务终端定义生成stub。你可以利用JAX-RPC实现的客户端API javax.xml.rpc.Stub来提供配置信息。
以下代码示范了上面提到的步骤:
package hello;
import javax.xml.rpc.Stub;
public class HelloClient {
public static void main(String[] args) {
try {
HelloIF_Stub stub = (HelloIF_Stub)(newHelloWorld_Impl().getHelloIFPort());
stub._setProperty( javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, args[0]);
System.out.println(stub.sayHello("Duke!"));
command-line }
catch (Exception ex) {
ex.printStackTrace();
}
}
}
在上面的代码示例中,HelloClient是调用HelloWorld服务中的sayHello方法的一个独立程序。它通过stub,一个充当远程服务代理的本地对象,进行调用。请注意在代码清单中名为HelloIF_Stub和HelloWorldImpl的类,它们由wscompile工具生成。HelloIF前缀与服务定义接口相吻合,HelloWorld前缀对应配置文件中指定的服务名称。HelloWorldImpl类是JAX-RPC规范中描述的服务的实现。客户端通过调用HelloWorldImpl 类的getHelloIF方法获得对stub的引用,HelloWorldImpl类是在运行wscompile工具的时候创建的。
stub._setProperty方法的args[0]参数是一个表示目标服务端口的URI。
编译客户端代码
注意
确定在编译客户端代码之前运行了wscompile和wsdeploy工具。客户端代码引用了wscompile工具的产物。
wscompile -gen:client -d build/client -classpath build/shared
要编译客户端,请切换到保存客户端代码的目录并输入以下命令:
asant compile
该命令编译Java源代码。
组装客户端类生成JAR文件
你可以使用asant工具组装客户端类生成JAR文件。Asant是一个命令行接口工具。请输入以下命令:
asant jar
该命令创建客户端jar文件。
运行客户端
使用asant工具运行客户端。输入以下命令:
asant run
asant的运行目标会执行以下命令:
java -classpath cpath client endpoint
cpath – 包括已经创建的客户端jar文件的类路径,也包括作为JAX-RPC实现的一部分的几个其他JAR文件。
注意
为了远程运行客户端,所有的JAR文件必须存在于远程客户端系统中。
endpoint- http://localhost:8080/jaxrpc-hello/jaxrpc/HelloIF
这个URL的jaxrpc-hello部分是实现了HelloWorld服务的servlet的上下文,它对应jaxrpc-hello.war文件的前缀。字符串jaxrpc对应sun-web.xml配置描述文件中
可以通过build.xml文件完成编译、组装、和部署任务,并且可以通过它运行客户端。绑定在Sun Java System应用服务器中的本例的build.xml文件位于:
install_dir/samples/webservices/jaxrpc/simple/src
使用动态调用接口创建客户端
使用动态调用接口(DLL),客户端可以调用服务或是远程过程。利用可以动态查找服务及其远程过程的服务代理,客户端能够在运行时发现服务或是过程的名称。javax.xml.rpc.Service封装了两类不需要任何生成代码的动态调用。本节讲述创建动态客户端的过程。
使用动态代理创建JAX-RPC客户端
JAX-RPC客户端能够通过动态代理与web服务进行交互。动态代理是在运行时刻动态支持服务终端的类,不需要任何提前生成的stub。客户端通过调用javax.xml.rpc.Service接口的getPort()方法创建动态代理。客户端调用它的getPort()方法,传入Java服务定义接口和相应的web服务端口名称。它会返回服务定义接口的一个动态创建并且配置好的实现——动态创建的stub。
关于动态代理的更多信息,请访问如下URL:
http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html
下面给出的步骤解释了建立动态代理客户端的过程。
1. 确定在类路径中加入了必要的jar文件。想要了解向类路径中添加jar文件的更多信息,请参见"配置客户端环境 "。
2.创建一个使用动态代理调用服务的客户端类。
public class HelloClient {
....
....
}
3. 定义服务名称、端口名称、和包含想要访问的Web服务相关信息的WSDL名称。
String UrlString = endpoint;
String nameSpaceUri = "http://proxy.org/wsdl/HelloWorld";
String serviceName = "HelloWorld";
String portName = "HelloIFPort";
URL helloWsdlUrl = new URL(UrlString);
4. 获得默认ServiceFactory对象实现的一个实例。
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service helloService =serviceFactory.createService(helloWsdlUrl, new QName(nameSpaceUri,serviceName));
5. 为对象获得动态代理
HelloIF myProxy =(HelloIF)helloService.getPort( new QName(nameSpaceUri,portName), proxy.HelloIF.class);
在代码示例中,传入getPort()方法的是一个接口定义,它将被用作在运行时创建动态代理的模版。
6. 使用java.lang.reflect.InvocationHandler.Invoke()调用服务
System.out.println(myProxy.sayHello("Buzz"));
使用调用接口创建JAX-RPC客户端
在调用接口方法中,客户端动态地发现服务,配置远程调用,并且执行调用。客户端使用javax.xml.rpc.Call接口实现对JAX-RPC服务的动态调用。在运行时,客户端利用DII调用web服务中的远程过程。
DII调用对象方法支持两种类型的调用,即同步的请求-响应方式和单路方式。在请求-响应方式中,客户端利用调用对象的调用方法执行远程方法。然后,客户端等待直到操作完成,也就是说,直到响应被返回。在单路方式中,客户端使用调用对象的invokeOneWay方法进行远程调用。
以下步骤解释了能够通过调用接口方法调用web服务的客户端的创建过程:
1. 确定在类路径中添加了必要的jar文件。想要了解更多,请参见"配置客户端环境 "。
2. 在创建动态客户端的时候,定义想要访问的服务的名称以及端口名称。然后,利用ServiceFactory.newInstance()方法创建一个服务工厂。JAXR API支持用ServiceFactory.newInstance()方法来定义服务。想要了解更多信息,请参见
private static String qnameService = "HelloWorld";
private static String qnamePort = "HelloIF";
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(new QName(qnameService));
3. 从工厂中创建一个服务
Service service = Factory.createService(new QName(qnameService));
4. 从服务中创建一个调用对象并且传递端口名称及想要执行的操作名称作为参数。
QName port = new QName(qnamePort);
Call call = service.createCall();
call.setPortTypeName(port); call.setTargetEndpointAddress(endpoint);
5. 在执行实际方法调用之前设置属性。使用setProperty方法设置在JAX-RPC规范中列出的标准属性。
call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);
QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
call.setReturnType(QNAME_TYPE_STRING);
6. 设置操作名称
call.setOperationName(new QName(BODY_NAMESPACE_VALUE,"sayHello"));
call.addParameter("String_1", QNAME_TYPE_STRING, ParameterMode.IN);
String[] params = { new String("Duke!") };
用addParameter方法添加参数和在setOperationName方法中指定的操作类型。注意这些参数来自服务的WSDL文件。
7. 使用Call.invoke()方法调用服务
String result = (String)call.invoke(params);
Invoke方法调用了利用同步请求-响应交互方式在setOperationName方法中指定的操作。方法调用为调用指定了输入参数。
利用WSDL创建JAX-RPC客户端
以下步骤讲述了使用WSDL定位web服务并调用服务的动态客户端的创建过程。
1. 利用ServiceFactory.newInstance() 方法创建一个服务工厂
ServiceFactory serviceFactory = ServiceFactory.newInstance();
2. 从工厂创建一个服务对象。传入WSDL名称作为参数。
String nameSpaceUri = "http://hello.org/wsdl";
URL helloWsdlURL = new URL(URLstring);
3. 创建一个serviceName对象,并且传递想要调用的服务名称作为参数。
String serviceName = "HelloWorld";
4. 创建一个portName对象并指定端口名称。
String portName = "HelloIFport";
5. 创建一个OperationName对象并指定想要调用的服务操作名称。
String operationName = "sayHello";
6. 创建一个服务,传递WSDL位置和想要调用的服务名称作为参数。
Service helloService = serviceFactory.createService(helloWsdlURL, new QName(nameSpaceUri, serviceName"));
7. 创建一个Call对象,传递端口名称以及想要执行的操作作为参数。
Call call = helloService.createCall(portName, operationName);
8. 通过Call.Invoke()方法调用服务。
String result = String call.Invoke(helloService);
组装并部署JAX-RPC客户端
利用wsdeploy 命令工具,JAX-RPC客户端能够被绑定到可部署的WAR文件之上。wsdeploy 命令工具读取JAX-RPC运行时描述文件jaxrpc-ri.xml和web应用程序配置描述文件web.xml。
组装和部署JAX-RPC客户端包括以下步骤:
1. 创建JAX-RPC运行时描述文件,文件名称必须是jaxrpc-ri.xml。请参见" jaxrpc-ri.xml文件"。
2. JAX-RPC客户端是一个web模块。创建一个web模块配置描述文件web.xml。关于web.xml的信息,请参见Sun ONE应用服务器开发人员web应用指南
3. 使用wsdeploy命令工具创建一个可部署的WAR文件。关于wsdeploy命令工具,请参见"wsdeploy工具"。
4.使用asadmin 部署命令部署WAR文件。
可以通过一个ant build.xml 文件完成组装、部署、以及运行JAX-RPC客户端的任务。捆绑在Sun ONE应用服务器中的本例的build.xml文件可以从以下位置得到:
install_dir/samples/webservices/jax-rpc/simple/src
示例应用程序