Java RPC通信机制之SOAP:应用Apache Axis进行Web Service开发(转)

    技术2022-05-12  14

    Java RPC 通信机制之 SOAP:应用 Apache Axis进行 Web Service开发

    一、概述

    SOAP 原意为 Simple Object Access Protocol (简单对象访问协议),是一个用于分布式环境的、轻量级的、基于 XML 进行信息交换的通信协议( SOAP is an XML based protocol used to exchange information throughout a distributed environment )。

    以下是 w3c 网站上的定义:

    SOAP Version 1.2 (SOAP) is a lightweight protocol intended for exchanging structured information in a decentralized, distributed environment. It uses XML technologies to define an extensible messaging framework providing a message construct that can be exchanged over a variety of underlying protocols. The framework has been designed to be independent of any particular programming model and other implementation specific semantics.

    可以认为 SOAP XML-RPC 的高级版本,二者基于相同的原理:利用 HTTP + XML 封装进行 RPC 调用。

    SOAP 最初由 MS 发起研究,用以解决 MTS/COM 资源消耗大,不够轻巧等问题,后逐渐被 IBM 等巨头接纳并加入研究,现已提交 W3C ,成为 Web Service 应用传输标准。对于轻量级、可扩展 Web Service 应用协议的需求促成了 SOAP 的广泛应用,也间接促进了 XML 的流行。关于相关历史的更多信息,见 http://www.microsoft.com/china/MSDN/library/WebServices/WebServices/SOAPSpecificationIndexPage.mspx http://www-128.ibm.com/developerworks/cn/webservices/ws-ref1/index.html

    二、 SOAP数据包结构解析

    SOAP 的消息被称为一个 SOAP Envelope ,包括 SOAP Header SOAP Body 。其中, SOAP Header 可以方便的插入各种其它消息来扩充 Web Service 的功能,比如 Security (采用证书访问 Web Service ), SOAP Body 则是具体的消息正文,也就是 Marshall 后的信息。

    SOAP 调用的时候,也就是向一个 URL (比如 http://api.google.com/search/beta2 )发送 HTTP Post 报文(根据 SOAP 规范, HTTP Get 报文也可被支持),调用方法的名字在 HTTP Request Header SOAP-Action 中给出,接下来就是 SOAP Envelope 了。服务端接到请求,执行计算,将返回结果 Marshall XML ,用 HTTP 返回给客户端。

    以下是一个典型的 SOAP 数据包:

    < s:Envelope xmlns:s = "http://www.w3.org/2003/05/soap-envelope ">

          < s:Header >

                < m:transaction xmlns:m = "soap-transaction " s:mustUnderstand = "true ">

                      < transactionID > 1234</ transactionID >

                </ m:transaction >

          </ s:Header >

          < s:Body >

                < n:purchaseOrder xmlns:n = "urn:OrderService ">

                      < from >

                            < person > Christopher Robin</ person >

                            < dept > Accounting</ dept >

                      </ from >

                      < to >

                            < person > Pooh Bear</ person >

                            < dept > Honey</ dept >

                      </ to >

                      < order >

                            < quantity > 1</ quantity >

                            < item > Pooh Stick</ item >

                      </ order >

                </ n:purchaseOrder >

          </ s:Body >

    </ s:Envelope >

    其中包含了一些 SOAP 规范定义的标签,同时也可以包含一些具体应用相关的标签。

    Note:

    如果你是一个普通的应用开发者,以上介绍已经足够了,因为相应的 SOAP 应用平台会负责完成相应 SOAP 数据包的打包和解析;如果你是一个 SOAP 应用平台的实现者,关于 SOAP 基础理论的更多介绍可参考《 Programming Web Services with SOAP 》一书或 SOAP Specification http://www.w3.org/TR/soap12-part0/ )。

    三、安装 Apache Axis

    Apache Axis 本身也是一个 Web Project ,它内建了对 SOAP 的编码、解析,并为 Client 提供了一些使用 SOAP Service API ,同时,为 Web Service 的发布提供管理,并对 Client 提交的处理请求作出响应。对于基于 Axis 的应用而言,我们可以将注意力完全放在具体 Service Client 的设计上,而无需考虑中间的传输过程(对于 Client 而言,还需要使用一些 Axis 提供的访问 SOAP 服务的特定 API ),这一点是与 XML RPC 不同的地方。

    Apache Axis 可以从 http://ws.apache.org/axis/ 下载,当前的最新版本是 1.4

    安装 Axis 的过程很简单:

    1 、解压 Axis 到任意目录下;

    2 、拷贝 Axis 目录下的 webapps/axis 目录到 %TOMCAT_HOME%/webapps 下;

    3 、为了便于编译和测试程序,添加环境变量 :

    AXIS_HOME      Axis 的解压目录

    AXIS_LIB      %AXIS_HOME%/lib

    AXISCLASSPATH      %AXIS_LIB%/axis.jar;%AXIS_LIB%/commons-discovery-0.2.jar;%AXIS_LIB%/commons-logging-1.0.4.jar;%AXIS_LIB%/jaxrpc.jar;%AXIS_LIB%/saaj.jar;%AXIS_LIB%/log4j-1.2.8.jar

    完成上述工作后,启动 Tomcat ,并用 IE 打开: http://localhost:8080/axis/ ,点击其中的 Validation List 两个链接,如果没有报告任何错误,则说明 Axis 安装成功。

    关于 Apache Axis 安装的更多信息可以参考官方文档: http://ws.apache.org/axis/java/install.pdf

    四、举例

    有了上面对 SOAP 的基本理解,下面我们体验一下 Apache Axis 1.4 提供的 SOAP 服务。

    以下面 EchoService 为例:

    public class EchoService {

          public String echoString(String name) {

                return name;

          }

    }

    其对应的 Client 程序如下所示:

    package demo.soap;

     

    import org.apache.axis.client.Call;

    import org.apache.axis.client.Service;

     

    import javax.xml.namespace .QName;

     

    public class EchoClient {

          public static void main(String [] args) {

                try {

                      String endpoint = "http://localhost:8080/axis/EchoService.jws" ;

                      // Create Service and Call object to set up a SOAP RPC

                      Service service = new Service();

                      Call call = (Call)service.createCall();

                      // Tells which service and method will be invoked

                      call.setTargetEndpointAddress(new java.net.URL(endpoint));

                      call.setOperationName(new QName("echoString" ));

                      // Invoke method with required parameters

                      String ret = (String)call.invoke(new Object[] { "Hello!" });

     

                      System.out.println("Sent 'Hello!', got '" + ret + "'" );

                } catch (Exception e) {

                      System.err.println(e.toString());

                }

          }

    }

    对于 Client 程序而言,对 Axis Service 进行访问的基本方法是:

    1 、创建 Service Call 对象;

    2 、设置 Call 对象属性,如访问点(标明将访问哪个 Axis Service )及方法名等;

    3 、传入参数数组,调用 Call 对象的 invoke 方法。

    可使用如下命令编译 EchoClient.java

    javac -cp %AXISCLASSPATH% EchoClient.java

    Axis 中,存在两种发布 SOAP Service 的方法。

    方法一:

    将源程序 EchoService.java 拷贝到 %TOMCAT_HOME%/webapps/axis 下,并将其后缀改为 .jws 即可。

    第一种方法非常的简单,但是第一种发布方法存在几个重要的限制:

    1 、不能指定 package

    2 、需要有 Service 的源码;

    因此常常不能满足我们的需要。

    方法二:

    第二种发布 Axis Service 的方法需通过配置来完成。

    以下面的 HelloService 为例(与前面的 EchoService 基本没有什么区别,但其中使用了 package ):

    package demo.soap;

     

    public class HelloService {

          public String sayHello() {

                return "Hello World!" ;

          }

    }

    要发布上面的 Service ,需编写如下的配置文件:

    < deployment xmlns = "http://xml.apache.org/axis/wsdd/ " xmlns:java = "http://xml.apache.org/axis/wsdd/providers/java ">

          < service name = "HelloService " provider = "java:RPC ">

                < parameter name = "className " value = "demo.soap.HelloService "/>

                < parameter name = "allowedMethods " value = "* "/>

          </ service >

    </ deployment >

    将上述内容保存为 %TOMCAT_HOME%/webapps/axis/WEB-INF/deploy.txt ,并在其所在目录下执行:

    java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt

    生成 server-config.wsdd 文件,打开该文件看一下,可以看到 HelloService 的相关信息已被添加到该文件,此外,还包括一些默认的配置信息以及 AdminService Version 两个基础服务。

    以下是 HelloService Client 程序的相关代码:

    package demo.soap;

     

    import org.apache.axis.client.Call;

    import org.apache.axis.client.Service;

     

    public class HelloClient {

          public static void main(String [] args) throws Exception {

                String endpoint = "http://localhost:" + "8080" + "/axis/services/HelloService" ; // Attention: A little difference

     

                Service service = new Service();

                Call call = (Call)service.createCall();

                call.setTargetEndpointAddress(new java.net.URL(endpoint));

                call.setOperationName("sayHello" );

     

                String res = (String)call.invoke(new Object[] {});

     

                System.out.println(res);

          }

    }

    与前面的 EchoClient 的区别仅在于访问点稍有不同。

    发布后如何删除对应的 Service 呢?要删除上面发布的 HelloService 服务,只需在 %TOMCAT_HOME%/webapps/axis/WEB-INF 目录下添加如下的 undeploy.txt 描述文件,其内容如下:

    < undeployment xmlns = "http://xml.apache.org/axis/wsdd/ ">

          < service name = "HelloService "/>

    </ undeployment >

    然后执行:

    java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt

    以更新 server-config.wsdd 文件。

    刷新一下页面:

    http://localhost:8080/axis/servlet/AxisServlet

    将看到前面已发布的对应的 Service 已被删除。

    如果以后还要发布新的 Service ,你可以选择直接更新上面产生的 server-config.wsdd 文件,或者重复上面的步骤。

    Note :除了发布自己的 Web Service Axis ,你也可以将 Axis 集成到自己的 Web Application ,具体方法见 http://ws.apache.org/axis/java/install.pdf

    五、 Google Web API

    在继续下面的讨论之前,先娱乐一下,谈谈 Google Web API

    为了便于程序员体验 Google 的搜索服务,或者将 Google 的搜索服务集成到自己的应用中, Google 2002 发布了 Google Web API ,可以让世界各地的 Java .NET Perl Python 等程序员,免费地通过 Google 提供的 SOAP 开发接口以 Web Services 的方式,对 Google 下达查找指令,并且可以将结果使用于自己的程序或网页中。(不过使用上也有限制,它一天只允许未付费的程序员查找 1000 次。要使用前,必须先向 Google 注册帐号,取得一个 32 位长度的 license key ,每次呼叫查询时,必须带入这个 license key 。)

    通过使用 Google Web API ,能够从 Google 那儿以结构化数据的形式( xml 格式)取得检索结果,所带来的最大好处就是你可以根据你自己的意愿和设计,把这些检索结果显示你自己的页面上。这个页面上可显示自己的 logo 或一些其它的内容,就象自己编写的页面一样,而不必非要把 Google logo 显示在页面的顶部和底部。一句话,你可以控制 Google 的检索了,让 Google 为你的网站服务。(参考 5

    以下是使用 Proxy 连接 Google SOAP 服务的例子:

    java -cp googleapi.jar -Dhttp.proxyHost=xxx(proxy_host_ip/name) -Dhttp.proxyPort=xxx(proxy_port) com.google.soap.search.GoogleAPIDemo xxx(license_key) search billdavid

    其输出大致如下:

    Parameters:

    Client key = o917zHlQFHIr2+qMGPUYflB+j89LLbcX

    Directive  = search

    Args       = billdavid

    Google Search Results:

    ======================

    {

    TM = 0.694308

    Q  = "billdavid"

    CT = ""

    TT = ""

    CATs =

      {

      <EMPTY>

      }

    Start Index = 1

    End   Index = 10

    Estimated Total Results Number = 1280

    Document Filtering = true

    Estimate Correct = false

    Rs =

      {

     

      [

      URL  = "http://forums.vandyke.com/member.php?u=2050"

      Title = "VanDyke Software Forums - View Profile: <b>billdavid</b>"

      Snippet = "This is a discussion forum for users and evaluators of VanDyke Soft

    ware products."

      Directory Category = {SE="", FVN=""}

      Directory Title = ""

      Summary = ""

      Cached Size = "16k"

      Related information present = true

      Host Name = ""

      ],

     

      [

      URL  = "http://forums.vandyke.com/showthread.php?t=1393"

      Title = "Will you add two new features to SecureCRT? - VanDyke Software Forums

    "

      Snippet = "<b>billdavid billdavid</b> is offline. Registered User. Join Date:

    Apr 2006 <b>...</b><br>  Originally Posted by <b>billdavid</b>. I think the foll

    owing features are very useful: <b>...</b>"

      Directory Category = {SE="", FVN=""}

      Directory Title = ""

      Summary = ""

      Cached Size = "30k"

      Related information present = true

      Host Name = "forums.vandyke.com"

      ],

     

      [

      URL  = "http://www.beliefnet.com/user/profile_view.asp?userID=424089&popUp=1"

        Title = "Beliefnet Member Profile"

      Snippet = "Member Name: <b>billdavid</b>. Member since: 2/24/2003. Location: s

    ebring, florida , us.<br>  Sex: Male. Age: 53. Occupation: Other. Organizations

    and Affiliations: <b>...</b>"

      Directory Category = {SE="", FVN=""}

      Directory Title = ""

      Summary = ""

      Cached Size = "8k"

      Related information present = true

      Host Name = ""

      ],

    (下略 ...

    以下是通过 ethereal 抓到的本机发出的 Google Search 数据包:

    POST http://api.google.com/search/beta2 HTTP/1.0

    Host: api.google.com

    Content-Type: text/xml; charset=utf-8

    Content-Length: 864

    SOAPAction: "urn:GoogleSearchAction"

    <? xml version = '1.0 ' encoding = 'UTF-8 '?>

    < SOAP-ENV:Envelope xmlns:SOAP-ENV = "http://schemas.xmlsoap.org/soap/envelope/ " xmlns:xsi = "http://www.w3.org/1999/XMLSchema-instance " xmlns:xsd = "http://www.w3.org/1999/XMLSchema ">

          < SOAP-ENV:Body >

                < ns1:doGoogleSearch xmlns:ns1 = "urn:GoogleSearch " SOAP-ENV:encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/ ">

                      < key xsi:type = "xsd:string "> xxx…xxx </ key >

                      < q xsi:type = "xsd:string "> billdavid</ q >

                      < start xsi:type = "xsd:int "> 0</ start >

                      < maxResults xsi:type = "xsd:int "> 10</ maxResults >

                      < filter xsi:type = "xsd:boolean "> true</ filter >

                      < restrict xsi:type = "xsd:string "></ restrict >

                      < safeSearch xsi:type = "xsd:boolean "> false</ safeSearch >

                      < lr xsi:type = "xsd:string "></ lr >

                      < ie xsi:type = "xsd:string "> UTF-8</ ie >

                      < oe xsi:type = "xsd:string "> UTF-8</ oe >

                </ ns1:doGoogleSearch >

          </ SOAP-ENV:Body >

    </ SOAP-ENV:Envelope >

    com.google.soap.search.GoogleAPIDemo.java 的源代码可以在 googleapi 的压缩包中找到,其中演示了大部分基本 Google Web API 的用法,关于 Google Web API 的更多信息见参考 4

    六、 Axis2

    随着 Web Services 技术的演进, Apache Web Services 中间件也在不断发展,从第一代的 Apache SOAP ,第二代的 Axis ,逐渐发展成为第三代 Web Service 中间件 Axis2 。与 Axis 相比, Axis2 采用了性能更为优越的 XML 解析技术,采用面向组件的架构设计,从而具有更好的灵活性和可扩展性,并可支持异步通信需求等。参考 6 7 给出了利用 Axis2 进行 Web Service 开发的详细步骤。

    参考:

    1.   劳虎, SOAP Web services http://2tigers.net/html/tiger_column/article3.html

    2.   孟岩, Web Service : WebOS 中的 Function Call http://www.mengyan.org/blog/archives/2006/06/09/125.html

    3.   Axis 学习笔记, http://www.javaresearch.org/article/showarticle.jsp?column=5&thread=29576

    4.   Google, Google SOAP Search API, http://www.google.com/apis/

    5.   Patrick Chanezon, Patch For Google APIs to handle proxy settings, http://www.chanezon.com/pat/google_proxy_patch.html

    6.   Hilton ,关于 Google API 的学习, http://hedong.3322.org/archives/000274.html

    7.   Gopalakrishnan U Shreevidya Rao ,通过 Axis2 开发 Web 服务, http://www-128.ibm.com/developerworks/cn/webservices/ws-webaxis1/index.html

    8.   joyeta Apache Axis2(java web service) 備忘記, http://blog.matrix.org.cn/page/joeyta?entry=apache_axis2_java_web_service


    最新回复(0)