远程调用之XML-RPC

第一、XML-RPC介绍

    按照XML-RPC的规范,定义是:XML-RPC是工作在互联网上的远程程序调用协议。它可以允许软件运行在分布式的系统之上,通过互联网进行软件中程序之间的调用 其传输协议是HTTP,传送数据编码格式是XML。由于是通过HTTP传输数据,因此基于XML-RPC的软件不受操作环境环境、 编程语言等限制( 比如RMI只能用于java程序之间传输),由于是通过http协议传输,因此可以通过防火墙的限制,具有简单易用等特点。

第二、XML-RPC的使用

     XML-RPC只是一个协议,这里主要介绍一个实现了 XML-RPC协议的java 开源的框架apache的 XML-RPC 实现。

     第一步:去官方下载XML-RPC框架,地址是:Apache XML-RPC

     第二步: XML-RPC分为客户端跟服务端。

    创建服务端

XmlRpcServer主要是在服务端用来处理客户端发过来的请求并返回请求数据的类, 利用Apache的 XML-RPC有以下几种创建服务端的方式:

        1、 XmlRpcServer嵌入到一个Servlet容器中。

框架提供了一个Servlet的实现类: XmlRpcServlet,这个类自动的嵌入了 XmlRpcServer中,因此只需要将这个类部署到 Servlet容器中即可实现服务端。具体步骤是:

  • 定义处理远程调用的类
package org.apache.xmlrpc.demo;
    public class Calculator {
                public int add(int i1, int i2) {
                        return i1 + i2;
                }
                public int subtract(int i1, int i2) {
                        return i1 - i2;
                }
    }
  •  创建一个名称为XmlRpcServlet.properties的属性文件,里面用来存放处理远程调用的类,内容是Calculator=org.apache.xmlrpc.demo.Calculator,这里名字可以任意取,主要是用来在服务端注册这个实例类的。注意 :这个属性文件的名称是固定的,并且必须放在 org.apache.xmlrpc.webserver这个包下面.
  • 将这个Servlet配置到 web.xml文件中,如下:

 

<servlet>
        <servlet-name>XmlRpcServlet</servlet-name>
        <servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class>
        <init-param>
          <param-name>enabledForExtensions</param-name>
          <param-value>true</param-value>
          <description>
            Sets, whether the servlet supports vendor extensions for XML-RPC.
          </description>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>XmlRpcServlet</servlet-name>
        <url-pattern>/xmlrpc</url-pattern>
    </servlet-mapping>

 XmlRpcServlet有两个重要的配置属性:

    enabledForExceptions: 当服务端捕获到一个异常时,并且在web.xml文件中配置了这个属性为true,服务端会将这个异常转换成一个字节数组Byte[]返回给客户端。

   enabledForExtensions: 这个开源框架设置这个属性是为了扩展 XML-RPC协议的,因为完全符合原始协议 会有许多功能上的限制,比如一些基本的java原始数据类型都不能用,并且还要求发送的请求(request)需要设置content-length头,在http协议中,在请求头文件中设置这个属性意味着在发送请求或者相应之前,要把请求或者相应强制的写到字节数组中,而这是很耗时耗内存的工作。默认的情况下,是符合原始的XML-RPC协议的,也即这个属性值是false的,我们可以设置这个属性为true来扩展协议,需要注意的是 ,在client端与server端都有这个属性,只有在两端同时设置这个属性为true时才可用。设置这个属性后,就可以使用非常快速的节省内存的流模式,并且允许大部分的java对象传输:long, short, byte,float, DOM 节点, 实现了java.io.Serializable接口的对象实例 或者 JAXB对象。

这样我们就创建了一个XML-RPC服务端

 

        2、利用XML-RPC自带的HTTP Server实现服务端

利用WebServer作为服务端是经常用的方式,利用这种方式,需要手动的去读取配置文件,但是这里可以任意的命名属性配置文件,当然也可以在程序中指定属性。但是相对于嵌入到Servlet的方式,这种方式要慢一些。代码如下:

package org.apache.xmlrpc.demo.webserver;

  import java.net.InetAddress;

  import org.apache.xmlrpc.common.TypeConverterFactoryImpl;
  import org.apache.xmlrpc.demo.webserver.proxy.impls.AdderImpl;
  import org.apache.xmlrpc.server.PropertyHandlerMapping;
  import org.apache.xmlrpc.server.XmlRpcServer;
  import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;
  import org.apache.xmlrpc.webserver.WebServer;

  public class Server {
      private static final int port = 8080;

      public static void main(String[] args) throws Exception {
          WebServer webServer = new WebServer(port);
        
          XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
        
          PropertyHandlerMapping phm = new PropertyHandlerMapping();
          /* 从配置文件中加载.
           * The property file might look like:
           *   Calculator=org.apache.xmlrpc.demo.Calculator
           *   org.apache.xmlrpc.demo.proxy.Adder=org.apache.xmlrpc.demo.proxy.AdderImpl
           */
          phm.load(Thread.currentThread().getContextClassLoader(),
                   "MyHandlers.properties");

          /* 也可以像这样直接指定:
           * phm.addHandler("Calculator",
           *     org.apache.xmlrpc.demo.Calculator.class);
           * phm.addHandler(org.apache.xmlrpc.demo.proxy.Adder.class.getName(),
           *     org.apache.xmlrpc.demo.proxy.AdderImpl.class);
           */
          xmlRpcServer.setHandlerMapping(phm);
        
          XmlRpcServerConfigImpl serverConfig =
              (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
          serverConfig.setEnabledForExtensions(true);
          serverConfig.setContentLengthOptional(false);

          webServer.start();
      }
  }

 这样服务端就建好了。

     创建客户端

客户端主要是通过XmlRpcClient类来实现,这是一个无状态的线程安全的类,客户端的配置主要是通过这两个对象来配置:

 

名称
对象描述
ClientConfig 在这个接口类中设置一些原子属性,比如服务端rul、编码格式等,这个类的实现都是XmlRpcClientConfig的接口实现
TransportFactory

这个接口的任务是创建一个利用客户端的配置信息来与服务端对话的类,这里有两个这样的实现类,一个是创建 java.net里面的类(默认情况下是用这个)来与服务端进行通信,还有一个是利用Jakarta Commons Http Client的实现类

 

 

 

 

 

 

 

 

 

利用默认的TransportFactory的客户端代码片段:

    XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
    config.setServerURL(new URL("http://127.0.0.1:8080/xmlrpc"));
    XmlRpcClient client = new XmlRpcClient();
    client.setConfig(config);
    Object[] params = new Object[]{new Integer(33), new Integer(9)};
    Integer result = (Integer) client.execute("Calculator.add", params);

 利用 基于Jakarta HTTP Client的factory代码如下

    XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
    config.setServerURL(new URL("http://127.0.0.1:8080/XmlRpcServlet"));
    XmlRpcClient client = new XmlRpcClient();
    client.setTransportFactory(new XmlRpcCommonsTransportFactory(client));// 这里
   client.setConfig(config);
    Object[] params = new Object[]{new Integer(2), new Integer(3)};
    Integer result = (Integer) client.execute("Calculator.add", params);

 内置的TransportFactory的实现以及Config所可以设置的属性,可以参考官方文档。

注意 运行这个例子的时候会出现异常比如用到基于Jakarta HTTP Client的Factory时,因为这个开源包没有包含 Jakarta HTTP Client的jar包,因此需要到官网上下载这个jar包。

第三、总结

     总的来说,Apache XML-RPC简单易用,既兼容了XML-RPC的规范,有可以对其进行扩展,增强器功能性, 由于扩展了 XML-RPC的协议,因此所支持的java对象类型比较丰富 XML-RPC协议仅仅支持以下几种类型:

 Integer,Boolean,String,Double,java.util.Date,byte[],java.util.Map,Object[],java.util.List, 当设置了enabledForExtensions属性时,可以额外支持以下属性:

Byte,Float,Long,org.w3c.dom.Node,Short,java.io.Serializable,BigDecimal,BigInteger,java.util.Calendar。但是缺点也很明显,在客户端调用服务器的对外发布接口时,用的是XmlRpcClient类的excute方法,调用这个方法是,指定服务端的对外发布接口是通过字符串的形式指的的,比如"Calculator.add",这样就很难在编译时检查服务端对象是否有这个方法,只有在运行时才会检测到,并且,传递的这个方法的参数是放在一个List或者Object[]中的,很容易将方法参数的顺序颠倒,这也只能在运行时才能检测到。

     

 

 

 

你可能感兴趣的:(apache,xml,互联网,servlet,嵌入式)