Java分佈式通信之RMI

RMI概述

    在Java中實現遠程調用的方式主要有兩種技術,一個是RMI,一個是webservice,本次主要講解RMI技術。RMI是Remote Method Invocation縮寫,是Java用於透明遠程調用的重要機制,它使客戶機上運行的程序可以調用遠程服務器上的對象,在遠程調用中,客戶端只要擁有服務端提供的接口,通過此接口實現對遠程服務端的調用,它的目的在於對開發人員屏蔽橫跨不同JVM和網絡連接等細節,使得分佈在不同JVM上的對象像是存在於一個統一的JVM中一樣,可以很方便的互相通訊。


實現機制

    RMI 服務端通過啓動註冊對象監聽在某一端口上對外提供服務的接口,接口的實現類在註冊對象上註冊並命名。客戶端通過代理的訪問實現對服務端接口的訪問,即在客戶端需持有該接口,客戶端將要訪問服務端的對象的命名、方法名和參數封裝成一個對象,序列化後傳輸到服務端,服務端接受到請求後解析對象的命名、方法和參數,通過命名從已在服務端註冊的對象裏查找,之後結合要訪問的方法,利用反射技術找到對應的對象實例,傳入參數完成對服務端實例的調用。
    使用RMI時服務端的接口要實現remote接口,接口裏的每個方法必須拋出RemoteException,服務端的業務類實現此接口來提供相關的業務功能,然後通過UnicastRemoteObject.exportObject講此對象綁定至某個端口,最後將此對象註冊至本地的LocateRegistry並命名,下面舉個簡單例子。


示例代碼

服務端接口

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Business extends Remote
{
    public String action(String arg)throws RemoteException;

}

注意接口必須繼承Remote接口,接口裏的方法必須拋出RemoteException!
服務端實現類

public class BusinessImpl implements Business
{

    @Override
    public String action(String arg)
    {
        System.out.println("your  request has been received!!!:"+arg);
        return  arg;
    }

這裏偷個懶寫的簡單些。。。,意思到了。。。
服務端註冊類

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class Server
{
    public static void main(String[] args) throws RemoteException
    {

        //註冊命名
        String name="BusinessName";
        Business business=new BusinessImpl();
        //註冊類
        UnicastRemoteObject.exportObject(business, 0);
        //註冊監聽端口
        Registry registry=LocateRegistry.createRegistry(1099);
        registry.rebind(name, business);
    }
}

注:綁定服務的默認端口爲1099,如果使用了這個端口,則可以直接使用,當然你也可以自定義端口。
客戶端

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client
{
    public static void main(String[] args) throws Exception
    {
        //如果使用自定義端口,則調用LocateRegistry.getRegistry(String host,int port)
        Registry registry=LocateRegistry.getRegistry("localhost");
        String name="BusinessName";
        Business business=(Business)registry.lookup(name);
        business.action("哈哈,我是RMI客戶端");
    }
}

LocateRegistry方法摘要:

static Registry createRegistry(int port) 
          創建並導出接受指定 port 請求的本地主機上的 Registry 實例。
static Registry createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) 
          在本地主機上創建並導出 Registry 實例,該本地主機使用的是與該實例通信的自定義套接字工廠。
static Registry getRegistry() 
          返回本地主機在默認註冊表端口 1099 上對遠程對象 Registry 的引用。
static Registry getRegistry(int port) 
          返回本地主機在指定 port 上對遠程對象 Registry 的引用。
static Registry getRegistry(String host) 
          返回指定 host 在默認註冊表端口 1099 上對遠程對象 Registry 的引用。
static Registry getRegistry(String host, int port) 
          返回指定的 host 和 port 上對遠程對象 Registry 的引用。
static Registry getRegistry(String host, int port, RMIClientSocketFactory csf) 
          返回本地創建的指定 host 和 port 上對遠程對象 Registry 的遠程引用。

然後運行server類,在運行client類,控制檯輸出客戶端發送的並經過服務端處理的參數:

your  request has been received!!!:哈哈,我是RMI客戶端
總結

從上面的過程來看,RMI對服務器的IP地址和端口依賴很緊密,但是在開發的時候不知道將來的服務器IP和端口如何,但是客戶端程序依賴這個IP和端口。這也是RMI的侷限性之一。這個問題有兩種解決途徑:一是通過DNS來解決,二是通過封裝將IP暴露到程序代碼之外。
RMI的侷限性之二是RMI是Java語言的遠程調用,兩端的程序語言必須是Java實現,對於不同語言間的通訊可以考慮用Web Service或者公用對象請求代理體系(CORBA)來實現.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章