Java RPC通信机制之XML-RPC:Apache XML-RPC 3.0开发简介


摘要:

XML-RPC 是一种简单的,轻量级的通过 HTTP 协议进行 RPC 通信的规范。本文以 Apache XML-RPC 3.0 为基础,对 XML-RPC 的基本原理及 Apache XML-RPC 3.0 的主要特性进行了讨论和分析。

正文:

一、概述

XML-RPC 是一种简单的,轻量级的通过 HTTP 协议进行 RPC 通信的规范。一个 XML-RPC 消息就是一个请求体为 XML HTTP-POST 请求,被调用的方法在服务器端执行并将执行结果以 XML 格式编码后返回。

以下是通过 ethereal 抓到的一个典型的 XML-RPC 调用包(为便于阅读,进行了格式化):

POST /xmlrpc HTTP/1.1

Content-Type: text/xml

User-Agent: Apache XML RPC 3.0 (Jakarta Commons httpclient Transport)

Host: 135.252.156.147:8080

Content-Length: 260

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

< methodCall xmlns:ex = "http://ws.apache.org/xmlrpc/namespaces/extensions ">

      < methodName > Calculator.add</ methodName >

      < params >

            < param >

                  < value >

                        < i4 > 2</ i4 >

                  </ value >

            </ param >

            < param >

                  < value >

                        < i4 > 3</ i4 >

                  </ value >

            </ param >

      </ params >

</ methodCall >

而对应的返回数据包为:

HTTP/1.1 200 OK

Server: Apache XML-RPC 1.0

Connection: close

Content-Type: text/xml

Content-Length: 189

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

< methodResponse xmlns:ex = "http://ws.apache.org/xmlrpc/namespaces/extensions ">

      < params >

            < param >

                  < value >

                        < i4 > 5</ i4 >

                  </ value >

            </ param >

      </ params >

</ methodResponse >

其格式很简单,几乎是不言自明的,分别用 methodCall methodResponse 标签标识发送给 Server 的调用请求和 Server 的返回结果,请求方法的名称用 methodName 标识,参数用 params param 标识,而参数的类型标签则如下表所示:

Tag

Java Type

说明

<i4> or <int>

Integer/int

4 字节带符号整数值

<boolean>

Boolean

0 (false) or 1 (true)

<string>

String

字符串

<double>

Double

双精度带符号浮点值

<dateTime.iso8601>

java.util.Date

日期 / 时间

<base64>

byte[]

base64 编码的二进制数据

<struct>

java.util.Map

键值对,键为 String 类型,而值为任意有效类型

<array>

Object[]

java.util.List

对象数组

二、举例

下面举一个实际运用 XML-RPC 进行 RPC 调用的例子, XML-RPC 规范有多种针对不同语言的实现,这里我们使用的是 Apache XML-RPC3.0RC1

在开始之前,需到 http://jakarta.apache.org/commons/index.html 下载如下程序包:

commons-codec-1.3 (通用编码 / 解码算法实现,可参考 http://www.devx.com/Java/Article/29795/1954?pf=true http://jakarta.apache.org/commons/codec/userguide.html 来获得该软件包的详细信息)

commons-httpclient-3.0.1 HTTP 协议的客户端编程工具包,详细介绍见 http://www-128.ibm.com/developerworks/cn/opensource/os-httpclient/

将上述通用工具包解压后,拷贝其中的 jar 文件到 XML-RPC 解压目录的 dist 目录中。

并添加如下环境变量:

XMLRPC_HOME      XML-RPC 的解压目录

XMLRPC_LIB        %XMLRPC_HOME%/dist

XMLRPCCLASSPATH      %XMLRPC_LIB%/xmlrpc-common-3.0rc1.jar;%XMLRPC_LIB%/xmlrpc-server-3.0rc1.jar;%XMLRPC_LIB%/xmlrpc-client-3.0rc1.jar;%XMLRPC_LIB%/commons-httpclient-3.0.1.jar;%XMLRPC_LIB%/commons-codec-1.3.jar

 

整个应用很简单,通过 XML-RPC 调用 Server 端提供的 HelloHandler.sayHello 方法回显一个字符串信息。下面是 HelloHandler 接口及其实现类相关代码:

// Hello Handler.java

package demo.xmlrpc;

 

public interface H elloH andler {

      public String sayHello(String str );

}

 

// Hello HandlerImpl.java

package demo.xmlrpc;

 

public class H elloH andlerImpl implements Hello Handler {

      public String sayHello(String str){

            return "Hello, " + str + "!" ;

      }

}

以下是对应的 Server 端源代码:

// Server1 .java

package demo.xmlrpc;

 

import java.io.IOException;

import java.io.OutputStream;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.apache.xmlrpc.XmlRpcException;

import org.apache.xmlrpc.server.PropertyHandlerMapping;

import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;

import org.apache.xmlrpc.webserver.XmlRpcServletServer;

 

public class Server 1 extends HttpServlet {

      private XmlRpcServletServer server;

     

      public void init(ServletConfig pConfig) throws ServletException {

            super.init(pConfig);

            try {

                  // create a new XmlRpcServletServer object

                  server = new XmlRpcServletServer();

                  // set up handler mapping of XmlRpcServletServer object

                  PropertyHandlerMapping phm = new PropertyHandlerMapping();

                  phm.addHandler(" HelloH andler" , Hello Handler Impl .class );                 

                  server.setHandlerMapping(phm);

                  // more config of XmlRpcServletServer object     

                  XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl)server.getConfig();

                  serverConfig.setEnabledForExtensions(true );

                  serverConfig.setContentLengthOptional(false );

            } catch (XmlRpcException e) {

                  try {

                        log("Failed to create XmlRpcServer: " + e.getMessage(), e);

                  } catch (Throwable ignore) {

                  }

                  throw new ServletException(e);

            }

      }

     

      public void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse)

            throws IOException, ServletException {

            server.execute(pRequest, pResponse);

      }

}

以下是对应的 Client 端源代码:

// Client1 .java

package demo.xmlrpc;

 

import java.io.IOException;

import java.net.MalformedURLException;

import java.util.Vector;

import java.net.URL;

 

import org.apache.xmlrpc.XmlRpcException;

import org.apache.xmlrpc.client.XmlRpcClient;

import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

 

public class Client 1 {

      public static void main(String[] args) {

            try {

                  // config client

                  XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();

                  config.setServerURL(new URL("http://localhost:8080/jsp/XmlRpcServer" ));      // should be modified according to your configuration of jsp container

                  // create a new XmlRpcClient object and bind above config object with it

                  XmlRpcClient client = new XmlRpcClient();

                  client.setConfig(config);

                  // create parameter list

                  Vector <String> params = new Vector <String> ();

                  params.addElement("Tom" );

                  // execute XML-RPC call

                  String result = (String) client.execute(" HelloH andler.sayHello" , params);                 

                  System.out.println(result);

            } catch (MalformedURLException e) {

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

            } catch (XmlRpcException e) {

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

            } catch (IOException e) {

                  e.printStackTrace();

            }

      }

}

程序源码中已包含了详细的注释,这里就不作过多解释了。但需注意 XmlRpcDemo_Client 中的 ServerURL 信息应根据自己的的 jsp 容器的配置作相应调整,并需设置相应的 servlet-mapping 信息,在我的 jsp 目录( Tomcat5.5 Context 之一)下的 WEB_INF/web.xml 文件中存在如下的 servlet-mapping 信息:

< servlet >

      < servlet-name > XmlRpcServer</ servlet-name >

      < servlet-class > demo.xmlrpc.Server1</ servlet-class >

</ servlet >

< servlet-mapping >

      < servlet-name > XmlRpcServer</ servlet-name >

      < url-pattern > /XmlRpcServer</ url-pattern >

</ servlet-mapping >

并且,上述 Server1.class 及其他相关类文件已被拷贝到 jsp\WEB-INF\classes\demo\xmlrpc 目录下。

在启动 Tomcat 并执行

java -classpath %CLASSPATH%;%XMLRPCCLASSPATH% demo.xmlrpc.Client1.java

前,你应该将 %XMLRPC_HOME%/dist %XMLRPC_HOME%/lib 下的几个 jar 文件( source 就不用拷了)及前面下载的 commons-codec-1.3.jar 拷贝到 %TOMCAT_HOME%/common/lib jsp\WEB-INF\lib 下。

Note :除了上面这种方式,你可以无需编写任何 Server 端代码,仅通过简单配置完成上述功能,具体可参考: http://ws.apache.org/xmlrpc/server.html

接下来,作为比较,我们来看看 XML-RPC2.0 中应该如何实现上述功能。

以下是 2.0 版的 Server 程序:

// Server2 .java

package demo.xmlrpc;

 

import java.io.IOException;

import java.io.OutputStream;

 

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值