JAVA接口RMI技术

1.RMI技术java



1.1 RMI技术介绍程序员


RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体如今它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一。其实它能够被看做是RPC的Java版本。可是传统RPC并不能很好地应用于分布式对象系统。而Java RMI 则支持存储于不一样地址空间的程序级对象之间彼此进行通讯,实现远程对象之间的无缝远程调用。spring


RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通讯。因为JRMP是专为Java对象制定的,Java RMI具备Java的"Write Once,Run Anywhere"的优势,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统能够部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但因为JRMP是专为Java对象制定的,所以,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通讯。数据库


RMI可利用标准Java本机方法接口JNI与现有的和原有的系统相链接。RMI还可利用标准JDBC包与现有的关系数据库链接。RMI/JNI和RMI/JDBC相结合,可帮助您利用RMI与目前使用非Java语言的现有服务器进行通讯,并且在您须要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。安全


Java RMI极大依赖于接口,在须要建立一个远程对象时,程序员经过传递一个接口来隐藏底层的实现细节.客户端获得的远程对象句柄正好与本地的根代码相连,由后者负责透过网络通讯,这样一来,程序猿只关心如何经过本身的接口句柄发送消息.服务器


1.2 RMI远程方法调用的组成网络


一个正常的RMI系统有下面几个部分组成多线程

·远程服务的接口定义 框架

·远程服务接口的具体实现 运维

·桩(Stub)和框架(Skeleton)文件 

·一个运行远程服务的服务器 

·一个RMI命名服务,它容许客户端去发现这个远程服务 

·类文件的提供者(一个HTTP或者FTP服务器) 

·一个须要这个远程服务的客户端程序 


方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,而后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通讯,决定调用是应发往一个服务器仍是多个。传输层管理实际的链接,而且追踪能够接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序得到返回值。 


要完成以上步骤须要有如下几个步骤: 


一、 生成一个远程接口 


二、 实现远程对象(服务器端程序)


三、 生成占位程序和骨干网(服务器端程序)


四、 编写服务器程序 


五、 编写客户程序 


六、 注册远程对象 


七、 启动远程对象 


1.3 RMI远程方法调用的优势


从最基本的角度看,RMI是Java的远程过程调用(RPC)机制。与传统的RPC系统相比,RMI具备若干优势,由于它是Java面向对象方法的一部分。传统的RPC系统采用中性语言,因此是最普通的系统--它们不能提供全部可能的目标平台所具备的功能。 


RMI以Java为核心,可与采用本机方法与现有系统相链接。这就是说,RMI可采用天然、直接和功能全面的方式为您提供分布式计算技术,而这种技术可帮助您以不断递增和无缝的方式为整个系统添加Java功能。


RMI的主要优势以下: 


面向对象:RMI可将完整的对象做为参数和返回值进行传递,而不只仅是预约义的数据类型。也就是说,您能够将相似Java哈希表这样的复杂类型做为一个参数进行传递。而在目前的RPC系统中,您只能依靠客户机将此类对象分解成基本数据类型,而后传递这些数据类型,最后在服务器端从新建立哈希表。RMI则不需额外的客户程序代码(将对象分解成基本数据类型),直接跨网传递对象。 


可移动属性:RMI可将属性(类实现程序)从客户机移动到服务器,或者从服务器移到客户机。这样就能具有最大的灵活性,由于政策改变时只须要您编写一个新的Java类,并将其在服务器主机上安装一次便可。 


设计方式:对象传递功能使您能够在分布式计算中充分利用面向对象技术的强大功能,如二层和三层结构系统。若是您可以传递属性,那么您就能够在您的解决方案中使用面向对象的设计方式。全部面向对象的设计方式无不依靠不一样的属性来发挥功能,若是不能传递完整的对象--包括实现和类型--就会失去设计方式上所提供的优势。 


安  全:RMI使用Java内置的安全机制保证下载执行程序时用户系统的安全。RMI使用专门为保护系统免遭恶意小应用程序侵害而设计的安全管理程序,可保护您的系统和网络免遭潜在的恶意下载程序的破坏。在状况严重时,服务器可拒绝下载任何执行程序。 


便于编写和使用:RMI使得Java远程服务程序和访问这些服务程序的Java客户程序的编写工做变得轻松、简单。远程接口实际上就是Java接口。服务程序大约用三行指令宣布自己是服务程序,其它方面则与任何其它Java对象相似。这种简单方法便于快速编写完整的分布式对象系统的服务程序,并快速地制作软件的原型和早期版本,以便于进行测试和评估。由于RMI程序编写简单,因此维护也简单。 


可链接现有/原有的系统:RMI可经过Java的本机方法接口JNI与现有系统进行进行交互。利用RMI和JNI,您就能用Java语言编写客户端程序,还能使用现有的服务器端程序。在使用RMI/JNI与现有服务器链接时,您能够有选择地用Java从新编写服务程序的任何部分,并使新的程序充分发挥Java的功能。相似地,RMI可利用JDBC、在不修改使用数据库的现有非Java源代码的前提下与现有关系数据库进行交互。 


编写一次,处处运行:RMI是Java“编写一次,处处运行 ”方法的一部分。任何基于RMI的系统都可100%地移植到任何Java虚拟机上,RMI/JDBC系统也不例外。若是使用RMI/JNI与现有系统进行交互工做,则采用JNI编写的代码可与任何Java虚拟机进行编译、运行。 


分布式垃圾收集:RMI采用其分布式垃圾收集功能收集再也不被网络中任何客户程序所引用的远程服务对象。与Java 虚拟机内部的垃圾收集相似,分布式垃圾收集功能容许用户根据本身的须要定义服务器对象,而且明确这些对象在再也不被客户机引用时会被删除。 


并行计算:RMI采用多线程处理方法,可以使您的服务器利用这些Java线程更好地并行处理客户端的请求。Java分布式计算解决方案:RMI从JDK 1.1开始就是Java平台的核心部分,所以,它存在于任何一台1.1 Java虚拟机中。全部RMI系统均采用相同的公开协议,因此,全部Java 系统都可直接相互对话,而没必要事先对协议进行转换。


1.4 RMI和CORBA的关系


RMI 和 CORBA 常被视为相互竞争的技术,由于二者都提供对远程分布式对象的透明访问。但这两种技术其实是相互补充的,一者的长处正好能够弥补另外一者的短处。RMI 和 CORBA 的结合产生了 RMI-IIOP,RMI-IIOP 是企业服务器端 Java 开发的基础。1997 年,IBM 和 Sun Microsystems启动了一项旨在促进 Java 做为企业开发技术的发展的合做计划。两家公司特别着力于如何将 Java 用做服务器端语言,生成能够结合进现有体系结构的企业级代码。所须要的就是一种远程传输技术,它兼有 Java 的 RMI(Remote Method Invocation,远程方法调用)较少的资源占用量和更成熟的 CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构)技术的健壮性。出于这一须要,RMI-IIOP问世了,它帮助将 Java 语言推向了目前服务器端企业开发的主流语言的领先地位。 

(来源:sun;matrix.org.cn)


1.5 实例

1)定义一个远程接口 IHello.java


import java.rmi.Remote;


public interface IHello extends Remote {


public String sayHello(String name) throws java.rmi.RemoteException;


}


2)实现远程的接口(服务端就在此远程接口的实现类中) HelloImpl.java


import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements IHello {

    // 这个实现必须有一个显式的构造函数,而且要抛出一个RemoteException异常  

    protected HelloImpl() throws RemoteException {

        super();

    }

    /**

     * 说明清楚此属性的业务含义

     */

    private static final long serialVersionUID = 4077329331699640331L;

    public String sayHello(String name) throws RemoteException {

        return "Hello " + name + " ^_^ ";

    }

    public static void main(String[] args) {

        try {

            IHello hello = new HelloImpl();

            java.rmi.Naming.rebind("rmi://localhost:1099/hello", hello);

            System.out.print("Ready");

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}


3)新建一个RMI客户端调用程序 Hello_RMI_Client.java


import java.rmi.Naming;

public class Hello_RMI_Client {

    public static void main(String[] args) {

        try {

            IHello hello = (IHello) Naming.lookup("rmi://localhost:1099/hello");

                System.out.println(hello.sayHello("zhangxianxin"));

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}


4)编译并运行


4.1 用javac命令编译IHello.java、HelloImpl.java、Hello_RMI_Client.java


>javac *.java


4.2 用rmic命令生成桩和框架文件


 >rmic HelloImpl


成功执行完上面的命令能够发现生成一个HelloImpl_stub.class文件,若是JDK是使用Java2SDK,那么还能够发现多出一个HelloImpl_Skel.class文件。若是服务端程序与客户端程序在同一台机器上并在同一目录中,则能够省略掉接口实现类生成的桩和框架文件,但这就失去了使用RMI的意义,而若是要在不一样的JVM上运行时,客户端程序就必须得依靠服务端运程方法实现的桩和框架文件以及接口类。


4.3 运行注册程序RMIRegistry,必须在包含刚写的类的目录下运行这个注册程序。


>rmiregistry


注册程序开始运行了,不要管他,如今切换到另一个控制台运行服务器 


4.4 运行服务器HelloImpl


>java HelloImpl


当启动成功出现Ready...... 这个服务器就开始工做了,把接口的实现加载到内存等待客户端的联接。如今切换到第三个控制台,启动咱们的客户端。


4.5 启动客户端:为了在其余的机器运行客户端程序你须要一个远程接口(IHello.class) 和一个stub(HelloImpl_Stub.class)。 使用以下命令运行客户端


>java Hello_RMI_Client


当运行成功会在控制台打印:Hello zhangxianxin ^_^



备注:若是不想在控制台上开启RMI注册程序RMIRegistry的话,可在RMI服务类程序中添加LocateRegistry.createRegistry(1099); 以下所示:


修改后的HelloImpl.java代码以下:


import java.rmi.RemoteException;

import java.rmi.registry.LocateRegistry;

import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements IHello {

    // 这个实现必须有一个显式的构造函数,而且要抛出一个RemoteException异常  

    protected HelloImpl() throws RemoteException {

        super();

    }

    

    private static final long serialVersionUID = 4077329331699640331L;

    public String sayHello(String name) throws RemoteException {

        return "Hello " + name + " ^_^ ";

    }

    public static void main(String[] args) {

        try {

            IHello hello = new HelloImpl();

            LocateRegistry.createRegistry(1099); //加上此程序,就能够不要在控制台上开启RMI的注册程序,1099是RMI服务监视的默认端口

            java.rmi.Naming.rebind("rmi://localhost:1099/hello", hello);

            System.out.print("Ready");

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

    }


1.6简单实例二



如下用一个文件交换程序来介绍RMI的应用。这个应用容许客户端从服务端交换(或下载)全部类型的文件。第一步是定义一个远程的接口,这个接口指定的签名方法将被服务端提供和被客户端调用。


1.定义一个远程接口 


IFileUtil.java代码以下: 



import java.rmi.Remote;


import java.rmi.RemoteException;


public interface IFileUtil extends Remote {


public byte[] downloadFile(String fileName) throws RemoteException;


}

接口IFileDownload提供了一个downloadFile方法,而后返回一个相应的文件数据。



2.实现远程的接口 

  类FileImpl继承于UnicastRemoteObject类。这显示出FileImpl类是用来建立一个单独的、不能复制的、远程的对象,这个对象使用RMI默认的基于TCP的通讯方式。


FileUtilImpl.java代码以下:



import java.io.BufferedInputStream;


import java.io.File;


import java.io.FileInputStream;


import java.rmi.RemoteException;


import java.rmi.server.UnicastRemoteObject;


public class FileUtilImpl extends UnicastRemoteObject implements IFileUtil {


protected FileUtilImpl() throws RemoteException {


super();


}


private static final long serialVersionUID = 7594622080290821912L;


public byte[] downloadFile(String fileName) throws RemoteException{


File file = new File(fileName);


byte buffer[] = new byte[(int) file.length()];


int size = buffer.length;


System.out.println("download file size = "+size +"b");


if(size>1024*1024*10){//限制文件大小不能超过10M,文件太大可能导制内存溢出!


throw new RemoteException("Error:<The File is too big!>");


}


try {


BufferedInputStream input = new BufferedInputStream(


new FileInputStream(fileName));


input.read(buffer, 0, buffer.length);


input.close();


System.out.println("Info:<downloadFile() hed execute successful!>");


return buffer;


} catch (Exception e) {


System.out.println("FileUtilImpl: " + e.getMessage());


e.printStackTrace();


return null;


}


}


}



3.编写服务端 


(1)建立并安装一个RMISecurityManager实例。


(2)建立一个远程对象的实例。


(3)使用RMI注册工具来注册这个对象。


FileUtilServer.java 代码以下:


import java.rmi.Naming;


import java.rmi.RMISecurityManager;


public class FileUtilServer {


public static void main(String argv[]) {


try {


IFileUtil file = new FileUtilImpl();


//LocateRegistry.createRegistry(1099); //加上此程序,就能够不要在控制台上开启RMI的注册程序,1099是RMI服务监视的默认端口


Naming.rebind("rmi://127.0.0.1/FileUtilServer", file);


System.out.print("Ready");


} catch (Exception e) {


System.out.println("FileUtilServer: " + e.getMessage());


e.printStackTrace();


}

}

}

声明Naming.rebind("rmi://127.0.0.1/FileUtilServer", file) 中假定了RMI注册工具(RMI registry )使用并启动了1099端口。若是在其余端口运行了RMI注册工具,则必须在这个声明中定义。例如,若是RMI注册工具在4500端口运行,则声明应为:  Naming.rebind("rmi://127.0.0.1:4500/FileUtilServer", file) 


另外咱们已经同时假定了咱们的服务端和RMI注册工具是运行在同一台机器上的。不然须要修改rebind方法中的地址。





4.编写客户端 


客户端能够远程调用远程接口(FileInterface)中的任何一个方法。不管如何实现,客户端必须先从RMI注册工具中获取一个远程对象的引用。当引用得到后,方法downloadFile被调用。在执行过程当中,客户端从命令行中得到两个参数,第一个是要下载的文件名,第二个是要下载的机器的地址,在对应地址的机器上运行服务端。


FileUtilClient.java 代码以下:


import java.io.BufferedOutputStream;


import java.io.File;


import java.io.FileOutputStream;


import java.rmi.Naming;


public class FileUtilClient {


public static void main(String args[]) {


if (args.length != 3) {


System.out.println("第一个参数:RMI服务的IP地址");


System.out.println("第二个参数:要下载的文件名");


System.out.println("第三个参数:要文件保存位置");


System.exit(0);


}


try {


String name = "rmi://" + args[0] + "/FileUtilServer";


IFileUtil fileUtil = (IFileUtil) Naming.lookup(name);


byte[] filedata = fileUtil.downloadFile(args[1]);


if(filedata==null){


System.out.println("Error:<filedata is null!>");


System.exit(0);


}


File file = new File(args[2]);


System.out.println("file.getAbsolutePath() = "+file.getAbsolutePath());


BufferedOutputStream output = new BufferedOutputStream(


new FileOutputStream(file.getAbsolutePath()));


output.write(filedata, 0, filedata.length);


output.flush();


output.close();


System.out.println("~~~~~End~~~~~");


} catch (Exception e) {


System.err.println("FileUtilServer exception: " + e.getMessage());


e.printStackTrace();


}


}


}




5.运行程序

为了运行程序,咱们必须使用rmic来编译生成stubs和skeletons:


>rmic FileUtilImpl


这将会生成FileUtilImpl_Stub.class和FileUtilImpl_Skel.class两个文件。stub是客户端的代理,而skeleton是服务端的框架。服务端和客户端采用javac来编译(若是服务端和客户端在两个不一样的机器,则必须复制一个IFileUtil接口)。


使用rmiregistry或者start rmiregistry 命令来运行RMI注册工具到window系统默认的端口上:

> rmiregistry portNumber

此处的portNumber为端口,RMI注册工具运行以后,须要运行服务FileUtilServer,由于RMI的安全机制将在服务端发生做用,因此必须增长一条安全策略: grant{permission java.security.AllPermission "", "";};


为了运行服务端,须要有除客户类(FileUtilClient.class)以外全部的类文件。确认安全策略在policy.txt文件以后,使用以下命令来运行服务器。

> java -Djava.security.policy=policy.txt FileUtilServer


为了在其余的机器运行客户端程序,须要一个远程接口(IFileUtil.class)和一个stub(FileUtilImpl_Stub.class)。 使用以下命令运行客户端:

> java FileUtilClient fileName machineName savePath

  这里fileName是要下载的文件名,machineName 是要下载的文件所在的机器(也是服务端所在的机器),savePath 是要将下载过来的文件保存的路径(带文件名)。若是所有经过的话,当客户端运行后,则这个文件将被下载到本地。


1.7 Spring对RMI的支持


1.使用RMI暴露服务


使用Spring的RMI支持,你能够经过RMI基础设施透明的暴露你的服务。设置好Spring的RMI支持后,你会看到一个和远程EJB接口相似的配置,只是没有对安全上下文传递和远程事务传递的标准支持。当使用RMI调用器时,Spring对这些额外的调用上下文提供了钩子,你能够在此插入安全框架或者定制的安全证书。





2. 使用 RmiServiceExporter 暴露服务


使用 RmiServiceExporter,咱们能够把AccountService对象的接口暴露成RMI对象。可使用 RmiProxyFactoryBean 或者在传统RMI服务中使用普通RMI来访问该接口。RmiServiceExporter 显式地支持使用RMI调用器暴露任何非RMI的服务。 


固然,咱们首先须要在Spring BeanFactory中设置咱们的服务: 


<bean id="accountService" class="example.AccountServiceImpl">


    <!-- any additional properties, maybe a DAO? -->


</bean>

而后,咱们将使用 RmiServiceExporter 来暴露咱们的服务: 



<bean class="org.springframework.remoting.rmi.RmiServiceExporter">


<!-- does not necessarily have to be the same name as the bean to be exported -->


<property name="serviceName" value="AccountService"/>


<property name="service" ref="accountService"/>


<property name="serviceInterface" value="example.AccountService"/>


<!-- defaults to 1099 -->


<property name="registryPort" value="1199"/>


</bean>

正如你所见,咱们覆盖了RMI注册的端口号。一般,你的应用服务也会维护RMI注册,最好不要和它冲突。更进一步来讲,服务名是用来绑定下面的服务的。因此本例中,服务绑定在 rmi://HOST:1199/AccountService。在客户端咱们将使用这个URL来连接到服务。 


注意:咱们省略了一个属性,就是 servicePort 属性,它的默认值为0。 这表示在服务通讯时使用匿名端口。固然若是你愿意的话,也能够指定一个不一样的端口。 





3. 在客户端连接服务


咱们的客户端是一个使用AccountService来管理account的简单对象: 


public class SimpleObject {


  private AccountService accountService;


  public void setAccountService(AccountService accountService) {


    this.accountService = accountService;


  }


}

为了把服务链接到客户端上,咱们将建立另外一个单独的bean工厂,它包含这个简单对象和服务连接配置位: 


<bean class="example.SimpleObject">


<property name="accountService" ref="accountService"/>


</bean>


<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">


<property name="serviceUrl" value="rmi://HOST:1199/AccountService"/>


<property name="serviceInterface" value="example.AccountService"/>


</bean>

这就是咱们在客户端为支持远程account服务所须要作的。Spring将透明的建立一个调用器而且经过RmiServiceExporter使得account服务支持远程服务。在客户端,咱们用RmiProxyFactoryBean链接它。



1.8 Spring对RMI支持的实际应用实例


在OMAS系统中提供给业务系统的RMI客户反馈服务的实现服务暴露是经过Resource/modules/interfaces/spring-conf/serviceContext.xml配置文件实现的,而远程接口的实现类必须序列化(即实现Serializable接口)。


Resource/modules/interfaces/spring-conf/serviceContext.xml的内容以下:


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


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">


<beans default-autowire="byName" default-lazy-init="false">


<!-- service实现类的配置 -->


<bean id="fbWebService" class="com.ce.omas.interfaces.service.impl.FeedbackWebServiceImpl" />


<bean class="org.springframework.remoting.rmi.RmiServiceExporter">


<!-- does not necessarily have to be the same name as the bean to be exported -->


<property name="serviceName" value="FeedbackRMIService" />


<property name="service" ref="fbWebService" />


<property name="serviceInterface" value="com.ce.omas.interfaces.service.IFeedbackWebService" />


<!-- <property name="registryHost" value="rmi://192.168.100.7"/> -->


<!-- defaults to 1099 -->


<property name="registryPort" value="1199" />


</bean>


</beans>




对应的暴露的服务接口以下:


public interface IFeedbackWebService {


/**


 * <b>方法用途和描述:</b> 客户反馈RMI服务端接口方法<br>


 * <b>方法的实现逻辑描述:</b> 经过RMI提供服务,Spring支持的RMI远程调用


 * @param systemID : 业务系统的惟一标识


 * @param feedbackType :用户反馈的类型(1-系统BUG、2-系统易用性、3-客服人员态度、4-运维人员态度、5-其余)


 * @param feedbackContent :用户反馈的正文内容


 * @return 反馈是否成功 true | false


 */


public boolean setFeedback(String systemID, FeedbackType feedbackType,


String feedbackContent) throws OMASServiceException ;


}




暴露的服务接口实现以下:


public class FeedbackWebServiceImpl implements IFeedbackWebService,  Serializable {


private static Log _log = LogFactory.getLog(FeedbackWebServiceImpl.class);


private static final long serialVersionUID = -5532505108644974594L;


/**


 * 客户反馈服务接口


 */


private IFeedbackOperationService feedbackService;


/**


* 方法用途和描述: 注入运营模块的添加客户反馈的服务


* @param feedbackWebService 运营模块服务


 */


public void setFeedbackService(IFeedbackOperationService feedbackWebService) {


_log.info("注入运营模块的添加客户反馈的服务");


this.feedbackService = feedbackWebService;


}


/**


* 方法用途和描述: 外部接口子系统中添加客户反馈的方法


* @param systemID :业务系统ID


* @param feedbackType :反馈类型


* @param feedbackContent :反馈内容


* @return 操做是否成功 ture or false


 * @throws ServiceException 


 */


public boolean setFeedback(String systemID, FeedbackType feedbackType, String feedbackContent) throws OMASServiceException {


_log.info("进入到外部接口的添加客户反馈的方法");


if (BlankUtil.isBlank(systemID) || BlankUtil.isBlank(feedbackType)


|| BlankUtil.isBlank(feedbackContent)) {


_log.error("添加客户反馈的接口参数为空!");


throw new OMASServiceException("omas.interfaces.001");//添加客户反馈的接口参数为空


}


WebServiceFeedbackVO vo = new WebServiceFeedbackVO();


vo.setFeedbackType(String.valueOf(feedbackType.getValue()));


vo.setFeedbackContent(feedbackContent);


vo.setSystemID(systemID);


_log.info("调用运营子系统的添加客户反馈的方法开始!");


try {


if (feedbackService == null) {


_log.error("运营模块服务为空");


throw new OMASServiceException("omas.interfaces.002");//运营模块服务为空


}


feedbackService.addFeedbackOperation(vo);


} catch (ServiceException e) {


_log.error("调用运营子系统的添加客户反馈出现异常:"+e.getMessage());


if(ExceptionConstants.EXCEPTION_OMAS_FEEDBACK_VO.equals(e.getMsgKey())){//客户调用接口的对像为空


throw new OMASServiceException("omas.interfaces.003");


} if(ExceptionConstants.EXCEPTION_OMAS_FEEDBACK_SYSTEMID.equals(e.getMsgKey())){//业务系统标识ID为空


throw new OMASServiceException("omas.omasservice.010");


} if(ExceptionConstants.EXCEPTION_OMAS_FEEDBACK_SIZE.equals(e.getMsgKey())){//非法的业务系统惟一标识


throw new OMASServiceException("omas.interfaces.004");


} if(ExceptionConstants.EXCEPTION_OMAS_FEEDBACK_BASE.equals(e.getMsgKey())){//数据库访问出了一点小问题!


throw new OMASServiceException("omas.interfaces.005");


}


throw new OMASServiceException("omas.omasservice.000");//未捕获到的异常信息!


}


return true;


}


}


接口方法setFeedback(String, FeedbackType, String)的实现你们不用关心,其与RMI并没有关系,只是一些纯业务处理逻辑而已,要注意的是接口实现类必须实现 IfeedbackWebService和Serializable接口。



在客户本地的omasservice.jar包中客户反馈的RMI客户端的配置以下:


Resource/config/omasrmi-client.xml


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


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">


<beans default-autowire="byName" default-lazy-init="true">


<bean id="fbWebServiceProxy"


class="org.springframework.remoting.rmi.RmiProxyFactoryBean">


<property name="serviceUrl">


<value>rmi://127.0.0.1:1199/FeedbackRMIService</value>


</property>


<property name="serviceInterface">


<value>com.ce.omas.interfaces.service.IFeedbackWebService</value>


</property>


</bean>


<bean class="com.ce.omas.omasservice.service.impl.FeedbackRMIClientImpl">


<property name="feedbackWebService" ref="fbWebServiceProxy" />


</bean>


</beans>





客户端调用RMI服务的方法以下所示:


/**


* 方法用途和描述: 客户反馈:经过RMI方法与OMAS通信


* 方法的实现逻辑描述:


* @param feedbackType


* @param feedbackContent


* @return


* @throws OMASServiceException


*/


public static boolean setFeedback_RMIClient(String systemID, FeedbackType feedbackType, String feedbackContent) throws OMASServiceException {


if (systemID == null || "".equals(systemID)) {


_log.error("业务系统标识<SystemID>为空或不是对象");


throw new OMASServiceException("omas.omasservice.010");


}


String rmiClientConfigFilePath = PropertyReader .getValue(ConfigConstants.OMASSERVICE_CONFIG_PATH, ConfigConstants.RMI_CLIENT_CONFIG_FILEPATH);


if (rmiClientConfigFilePath == null || "".equals(rmiClientConfigFilePath)) {


_log.error("配置文件错误:Key<rmiClientConfigFile>为空或不存在");


throw new OMASServiceException("omas.omasservice.006");


}


_log.info("rmiClientConfigPath = " + rmiClientConfigFilePath);


ApplicationContext context = null;


try {


context = new ClassPathXmlApplicationContext(rmiClientConfigFilePath);


} catch (Exception e) {


_log.error("客户反馈:解析rmi-config.xml文件时出现异常:" + e);


_log.info("rmi-config.xml文件路径:"+rmiClientConfigFilePath);


throw new OMASServiceException("omas.omasservice.007");


}


IFeedbackWebService service = null;


try {


service = (IFeedbackWebService) context .getBean("fbWebServiceProxy");


} catch (Exception e) {


_log.error("从Spring的RMI客户端Bean配置文件获取服务对象时出现异常:" + e);


throw new OMASServiceException("omas.omasservice.009");


}


boolean bln = service.setFeedback(systemID, feedbackType, feedbackContent);


_log.info("反馈操做是否成功[true|false]:" + bln);


return bln;


}


2.Hessian



3.WebService

相关文章
相关标签/搜索