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