深入浅出JAX-WS 2.0

系统 1706 0

本文根据 SUN 官方网站 Enterprise Java Technologies Tech Tips 栏目上的一篇文章改写的,所有过程均调试通过。

一.前言

SOA 思想的核心在于 "S" ,凡是从服务的角度去看待系统功能,并且构建和实现应用,都可以认为是 SOA 的某种实现形式。下面一段要说的是: SOA 技术的核心在于 "O" --只有做到 Service-Orientation 的技术,才能真正称为 SOA 技术。

怎样才能算作 Service-Orientation ?我们再以 OO 进行类比: VB 之所以被称为基于对象 (Object-Based) 而不是面向对象 (Object-Oriented) 的语言,是因为 VB 的运行时结构不具有 VMT 等基本构造,语法上也不支持私有成员,继承等基础特性,两者结合,就造成无法支持封装,继承,多态等面向对象的关键技术。一句话, VB 不是围绕 对象 这个核心概念设计的语言。 对于 SOA 技术,它也可以从这个角度划分两个层次:一个是 SOA 运行时 相关结构标准,例如 SOAP WSDL,WS-* 等,相当于 OO 中的对象内部结构, VMT 构造等。另外一个则是语言和工具层面的支持,例如基于元数据的服务描述,支持 Web Service 的类库, Proxy 生成工具等,相当于 OO 语言中提供的基本 OO 语法,类库,编绎器等。这两个层次共同构成 SOA 体系结构中的要素,让人们能够围绕 服务 这个核心概念进行系统开发和应用。因此,一种技术架构,平台或产品要称作 SOA ,应当同时具备这一两方面的特征。

所以,下面将要讨论的 JAX-WS 技术,从上面的观点来看,也就是 SOA 技术的第二个层次,即语言和工具层面的支持 --Java ,例如基于元数据的服务描述,支持 Web Service 的类库, Proxy 生成工具等 .

Java API for XML Web Services JAX-WS 2.0, Java EE 5 平台的一个重要的部分。作为 Java API for XML-baseed RPC 1.1 JAX-RPC )的后续版本,在 JAX-RPC 1.1 , 开发人员需要写一个接口类 Service Endpoint Interface(SEI), JAX-WS 2.0 , 开发人员一上来就可以直接写自己的实现类 . 通过使用 annotations, 自动生成 SEI 和其他一些文件 . 这样有助于开发人员专注于自己想开发的部分 , 而不必要地分散精力去维护其他的一些附属文件 .

. 快速实践 JAX-WS2.0

下面通过一个两个数相加的简单例子来看看 ,JAX-WS 2.0 API 的应用过程 . 程序是一个独立的客户端传给服务端两个整数 , 经过服务端处理后 , 将结果返回到客户端并打印出来 .

. 环境配置 .

1. JDK 5.0 or higher

下载 : http://java.sun.com/javase/downloads/index.jsp

2. Java EE 5.0 App Server.

这个例子是基于 Java EE 5 的一个开源实现项目 GlassFish https://glassfish.dev.java.net/public/downloadsindex.html

本例子所需的基本代码的压缩包可以通过这个 链接 下载。里面包括了这个例子需要的代码,构建脚本和一个 build 文件。

环境变量的配置:

· GLASSFISH_HOME. 这个应该指向你安装 GlassFish 的目录 ( 比如,我系统上的是: J:/Sun/AppServer)

· ANT_HOME. 这个应该指向 ant 所安装的目录。在你下载 GlassFish bundle Ant 已经被包含在里面了。 ( 对于 Windows 系统,它是在 lib/ant 子目录 ) 。不过你也可以从 Apache Ant Project page. 下载 Ant 。对于这个例子需要 Apache ant 1.6.5

· JAVA_HOME. 这个应该指向你系统上安装的 JDK 5.0 or higher )的目录。

同时,把 ant bin 目录添加到 Path 环境变量中去 (J:/apache-ant-1.6.5/bin) ,当然了 JDK bin 目录也加进去了。

然后 下载例子的代码包 并且解压。根文件夹是 jaxws-techtip

深入浅出JAX-WS 2.0

endpoint/ 目录下有一个文件 Calculator.java

client/ 目录下有一个文件 JAXWSClient.java

. 编写构建服务端

随着第一步环境配置的完全,现在该开始构建一个 web 服务了。在这个例子里, web 服务是从一个 Java 类来开发的。为了构建这个 web 服务:

1 写一个端点实现类 ( endpoint implementation class)

2 编绎这个 端点实现类。

3 有选择的产生对 web 服务的运行必须具备的那些可移植的制品。

4 web 服务打包成一个 WAR 文件并且在 App Server 中部署它。

1 编写实现类 .

进到 endpoint/ 目录下,可以看到里面有一个文件 Calculator.java. 它是一个端点实现类,具备有对两个整数进行相加的简单服务。

JAX-WS 2.0 大量地依赖注释( annotations )的使用,它是 A Metadata Facility for the Java Programming Language (JSR 175) 描述的规范和 Web Services Metadata for the Java Platform (JSR 181) 描述的规范。

package endpoint;

import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService(
name
= " Calculator " ,
serviceName
= " CalculatorService " ,
targetNamespace
= " http://techtip.com/jaxws/sample "
)
public class Calculator ... {
public Calculator() ... {}

@WebMethod(operationName
= " add " ,action = " urn:Add " )
public int add( int i, int j) ... {
int k = i + j;
System.out.println(i
+ " + " + j + " = " + k);

return k;
}

}

研究上面的实现类 Calculator ,注意到类里的两个注释的使用 @WebService @WebMethod 。一个正确的端点实现类必须包含有一个 @WebService 注释。这个注释标注这个类将作为一个 web 服务对外开放。 @WebService name 属性表明了 web 服务描述语言 (WSDL) 里的端口类型 ( portType ) (在这个例子里是 ”Calculator” )。而 serviceName="CalculatorService" 对应的是一个 WSDL 里的服务元素 (service) targetNamespace 属性为 WSDL 说明了 XML 的命名空间。所有的这些属性都是可选的。对于这些属性的默认值是什么,请参考 Web Services Metadata for the Java Platform 规范, JSR 181

    
      
        再来看看另外一个重要的注释
      
      
        
          
            @WebMethod
          
          
            ,被它注释过的方法说明将它以一个
          
        
      
    
  
    
      
        
          
            
              web
            
            服务的方法暴露出来,被其他应用来调用。
          
        
      
      
        @WebMethod
      
      
        注释里的
        
          operationName
        
      
    
  
    
      
        声明了
        
          WSDL
        
        里的一个元素
        
          WSDL 
          
            operation
          
        
        (在这个例子里,
        
          ”add”
        
          ,
        
        另外一
      
    
  
    
      
        个属性
      
      
        
          action =("
        
        
          
            urn:Add
          
        
        
          "),
        
        
          它为
          
            WSDL
          
          还有一些从这个
          
            web
          
          服务操作
          
            (web service operation)
          
      
    
  
    
      
        
          成的元素声明了一个命名空间。这两个属性都是可选的。如果你没有列出来的
        
      
    
  
    
      
        
          话,
          
            WSDL
          
          操作
          
            (operation)
          
        
      
    
    
      
        
          的值将会默认为方法名,还有
          
            action
          
          值也会默认为
        
      
    
  
    
      
        
          服务的
        
      
      
        
          
            
              targetNamespace
            
            
          
        
      
    
  
    
      
        
          
          
        
      
      
        
          
            2 
          
        
      
      
        
          
            编绎实现类
          
        
      
    
  

写完了上面的实现类之后,你需要编绎它。点击 开始- > 程序- >Sun Microsystems >“Start Default Server” 启动应用服务器或者通过在 DOS 窗口下敲下面的命令来启动它: <GF_install_dir>/bin/asadmin start-domain domain1 ,其中 GF_install_dir 是你安装 GlassFish 的目录,也就是说先到 <GF_install_dir>/bin 目录下,然后用命令 asadmin start-domain domain1 来启动应用服务器。现在将目录转到 jaxws-techtip 文件夹下,运行下面的 ant 命令,也就是执行第一个任务 complie:

ant compile

执行这个命令就相当于执行以下的 javac 命令 ( 都是在同一行 )

javac -classpath $GLASSFISH_HOME/lib/javaee.jar -d

./build/classes/service/ endpoint/Calculator.java

3 web 服务的执行产生可移植的制品

这一步是可选的。如果在这个 web 服务的部署期间,他们没有和一个可配置的服务单元绑定, GlassFish 的部署工具能够自动地产生这些制品。然而对于刚刚接触 JAX-WS 来说,对于弄清楚整个编程模式来说,通过手动产生地会话会更有帮助,即运行下面的命令:

ant generate-runtime-artifacts

这个任务将会在 jaxws-techtip 目录下生成 build/generated 目录,并且运行了下面的 wsgen 命令 ( 都是在同一行 ):

$GLASSFISH_HOME/bin/wsgen -cp ./build/classes/service -keep -d ./build/classes/service –r ./build/generated -wsdl endpoint.Calculator

一个 WSDL 文件 (CalculatorService.wsdl) build/generated 目录下生成了,还在同个目录下生成了另外一个 schema 文件 (CalculatorService_schema1.xsd), 它为 CalculatorService.wsdl 定义了 schema

JavaBean 技术组件 ( JavaBeans ) 在编组 ( marshaling,java->XML ) 的方法调用,响应,还有 service-specific 异常 中起了很大的作用。这些类将会在 web 服务在一个应用服务器中运行的时候被使用。 JavaBean 类在 jaxws-techtip 目录下的 /build/classes/service/endpoint/jaxws 目录被生成了,这些类是:

Add.java

Add.class

AddResponse.java

AddResponse.class

4 打包并部署 WAR 文件

接下来你需要做的工作就是对服务进行打包和部署。为了做这个,你需要在一个部署描述符中详细说明这个服务。 Web 服务可以绑定成 servlet 的形式或者无状态的 session bean 形式打包成 Web Archive (WAR) 文件。在这个例子里把它绑定为一个 servlet

为了把这个服务打包成一个 WAR 文件,定位到 jaxws-techtip 文件夹,并且在 DOS 窗口上运行下面的命令:

ant pkg-war

对于这个 war 文件的结构,我们可以到 build.xml 文件里看看 pkg-war 目标:

< target name ="pkg-war" depends ="init-common">
< mkdir dir ="${assemble.dir}"/>
< echo message ="mybuildclassesdiris:${build.classes.dir}" level ="verbose"/>
< mkdir dir ="${build.classes.dir}/tmp"/>
< mkdir dir ="${build.classes.dir}/tmp/WEB-INF"/>
< mkdir dir ="${build.classes.dir}/tmp/WEB-INF/classes"/>
< mkdir dir ="${build.classes.dir}/tmp/WEB-INF/wsdl"/>
< copy file ="${web.xml}"
tofile
="${build.classes.dir}/tmp/WEB-INF/web.xml" failonerror ="false"/>
< copy todir ="${build.classes.dir}/tmp/WEB-INF/classes">
< fileset dir ="${build.classes.dir}/service">
< include name ="**/*.class"/>
< include name ="**/${handler.name}"/>
</ fileset >
</ copy >
< copy todir ="${build.classes.dir}/tmp/WEB-INF/wsdl">
< fileset dir ="${build.generated.dir}">
< include name ="**/*.*"/>
</ fileset >
</ copy >
< echo message ="Creatingwarfile${assemble.dir}/${appname}-web.war" level ="verbose"/>
< jar jarfile ="${assemble.dir}/${appname}-web.war" update ="true">
< fileset dir ="${build.classes.dir}/tmp" casesensitive ="yes">
< include name ="**/*class*"/>
< include name ="**/${handler.name}"/>
</ fileset >
< fileset dir ="${build.classes.dir}/tmp/" casesensitive ="true">
< include name ="WEB-INF/web.xml"/>
</ fileset >
< fileset dir ="${build.classes.dir}/tmp" casesensitive ="yes">
< include name ="WEB-INF/wsdl/*.*"/>
</ fileset >
</ jar >
< echo message ="createdwarfile${assemble.dir}/${appname}-web.war" level ="verbose"/>
</ target >

我们可以通过执行下面的命令来部署已经生成的 war 文件:

ant deploy-app

这等同于执行下面的 asadmin 部署命令 ( 都是在同一行 )

bash$GLASSFISH_HOME/bin/asadmin deploy --user admin

--passwordfile passwd --host localhost --port 4848

--contextroot jaxws-webservice --upload=true --target server

编写构建客户端

在你部署完这个 web 服务之后,你可以通过一个客户端程序来访问它。下面是构建这个客户端的步骤:

1 编写客户端

2 生成编绎这个客户端必须要有的可移植制品。

3 编绎客户端。

4 运行客户端。

5.1 编写客户端

下面的程序, JAXWSClient, 是一个独立的客户端程序,它在这个例子所提供的代码里可以找到。这个客户端类调用了部署好的服务的一个 add 操作十次,从数字 0 9 挨个加 10.

package client;
import
javax.xml.ws.WebServiceRef;
import
com.techtip.jaxws.sample.CalculatorService;
import
com.techtip.jaxws.sample.Calculator;
public class JAXWSClient ...
{
@WebServiceRef(wsdlLocation=
"http://localhost:8080/jaxws-webservice/CalculatorService?WSDL")
static
CalculatorServiceservice;
public static void main(String[]args) ...
{
try ...
{
JAXWSClientclient=
new
JAXWSClient();
client.doTest(args);
}
catch (Exceptione) ...
{
e.printStackTrace();
}
}
public void doTest(String[]args) ...
{
try ...
{
System.out.println(
"Retrievingportfromtheservice"+service);
Calculatorport=service.getCalculatorPort();
System.out.println(
"Invokingaddoperationonthecalculatorport");
for ( int i=0;i>10;i++) ...
{
int
ret=port.add(i,10);
if (ret!=(i+10)) ...
{
System.out.println("Unexpectedgreeting"+ret);
return
;
}
System.out.println(
"Adding:"+i+"+10="+ret);
}
}
catch (Exceptione) ...
{
e.printStackTrace();
}
}
}

研究下上面代码的特点,在 JAXWSClient 类里的 @WebServiceRef 注释是用来定义一个 web 服务的引用。 @WebServiceRef 注释的 wsdlLocation 参数它指向了一个所要引用的服务的 WSDL 文件。 @WebServiceRef 注释支持其它的可选属性,就像在 JSR 224 里所说的。静态变量名 service 将会被客户端容器在运行时被动态地注入。

注意到 JAXWSClient import 语句:

com.techtip.jaxws.sample.CalculatorService and com.techtip.jaxws.sample.Calculator .

这些 import 语句是对那些在下一步里将要产生的可移植制品的声明。 CalculatorService 是服务实现类的可移植制品。 Calculator 是一个对于服务端点的 Java 接口,它是从 @WebServiceRef 注释中的 wsdlLocation 属性所说明的 WSDL 文件生成的。

这个客户端从 getWebServiceRefNamePort 方法得到一个 CalculatorService ,从而得到一个端点 Calculator 接口 Calculator port = service.getCalculatorPort();WebServiceRefName @WebServiceRef 注释的 name 属性,或者说是在生成的 WSDL 文件里 WSDP 端口的值。在获得了这个端点后,客户端调用了十次加的操作。

5.2 生成客户端的可移植的制品

就像在之前所提到的, CalculatorService Calculator 都是可移植的制品。为了生成客户端所需的所有制品,定位到 jaxws-techtip 文件夹,并且在 DOS 窗口下输入下面的命令:

ant generate-client-artifacts

这相当于执行下面的 wsimport 命令 ( 都在同一行里 )

$GLASSFISH_HOME/bin/wsimport -keep-d ./build/classes/client

http://localhost:8080/jaxws-webservice/CalculatorService?WSDL

这将会在 jaxws-techtip 文件夹的 build/classes/client/com/techtip/jaxws/sample 目录下生成以下的制品:

Add.java

Add.class

AddResponse.java

AddResponse.class

Calculator.java

Calculator.class

CalculatorService.java

CalculatorService.class

package-info.java

package-info.class

ObjectFactory.class

ObjectFactory.java

5.3 编绎客户端类

下一步需要做的工作就是编绎客户端类。我们可以通过输入下面的命令来完成这项工作:

ant compile-client

ant 编绎任务将会编绎 client/JAXWSClient 并且把 class 文件写到 build /classes/client 子目录下。它等同于运行下面的命令 ( 都是在同一行 )

javac -d ./build/classes/client

-classpath $GLASSFISH_HOME/lib/javaee.jar:

$GLASSFISH_HOME/lib/appserv-ws.jar:

./build/classes/client client/JAXWSClient.java

5 4 运行客户端

为了了解这个例子是如何工作的,运行下面的命令:

ant runtest-jaxws

它就相当于在 build/classes/client 文件夹下, 运行下面的命令:

$GLASSFISH_HOME/bin/appclient -mainclass client.JAXWSClient

DOS 窗口可以看到类似下面的输出:

runtest-jaxws:

[echo] Executing appclient with client class as

client.JAXWSClient

[exec]Retrieving port from the service

com.techtip.jaxws.sample.CalculatorService@162522b

[exec]Invoking add operation on the calculator port

[exec]Adding : 0 + 10 = 10

[exec]Adding : 1 + 10 = 11

[exec]Adding : 2 + 10 = 12

[exec]Adding : 3 + 10 = 13

[exec]Adding : 4 + 10 = 14

[exec]Adding : 5 + 10 = 15

[exec]Adding : 6 + 10 = 16

[exec]Adding : 7 + 10 = 17

[exec]Adding : 8 + 10 = 18

[exec]Adding : 9 + 10 = 19

all:

BUILD SUCCESSFUL

Total time: 6 seconds

深入浅出JAX-WS 2.0


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论