1. 程式人生 > >遠端方法呼叫——RMI

遠端方法呼叫——RMI

RMI

RMI  (Remote  Method  Invocation)是Java用於實現透明遠端呼叫的重要機制。在遠端呼叫中,客戶端僅有伺服器端提供的介面 。通過此介面實現對遠端伺服器端的呼叫。威力就體現在它強大的開發分散式網路應用的能力上,是純Java的網路分散式應用系統的核心解決方案之一。其實它可以被看作是RPCJava版本。但是傳統RPC並不能很好地應用於分散式物件系統。而Java RMI 則支援儲存於不同地址空間的程式級物件之間彼此進行通訊,實現遠端物件之間的無縫遠端呼叫。


Sun  JDK  6 .0 以前版本中的R M I 實現均是基於TCP/IP+BIO 方式的,RMI 伺服器端通過啟動RMI 註冊物件在一個埠上監聽對外提供的介面,其實現例項以字串的方式繫結到RMI 註冊物件上。RMI客戶端通過Proxy的方式代理了對伺服器端介面的訪問,RMI 客戶端將要訪問的伺服器端物件字串、方法和引數封裝成一個物件,序列化成流後通過TCP/IP + BIO 傳輸到 RMI 伺服器端。RMI 伺服器端接收到客戶端的請求物件後,解析其中的物件字串、方法及引數,通過物件字串從 RMI 註冊物件上找到提供業務功能的例項,之後結合要訪問的方法來反射獲取到方法例項物件,傳入引數完成對伺服器端物件例項的呼叫,返回的結果則序列化為流以 TCP/IP + BIO 方式返回給客戶端,客戶端在接收到此流後反序列化為物件,並返冋給呼叫者。


簡單例子

遠端呼叫介面:

/**
 * 遠端介面<br/>
 * 定義一個遠端介面,必須繼承Remote介面
 * 
 * @author Joeson
 * @since 07/2014
 */
public interface HelloRMI extends Remote
{
	// 其中需要遠端呼叫的方法必須丟擲RemoteException異常
	public String hello() throws RemoteException;
}


遠端呼叫介面實現:

/**
 * 
 * 遠端呼叫實現類<br/>
 * 需要繼承UnicastRemoteObject類,同時因為UnicastRemoteObject的構造方法丟擲了RemoteException異常,
 * 因此這裡預設的構造方法必須寫,必須宣告丟擲RemoteException異常。
 * 
 * @author Joeson
 * @since 07/2014
 *
 */
public class HelloRMIImpl extends UnicastRemoteObject implements HelloRMI
{

	public HelloRMIImpl() throws RemoteException
	{
		super();
		// TODO Auto-generated constructor stub
	}

	@Override
	public String hello() throws RemoteException
	{
		return "Hello, RMI";
	}

}


RMI伺服器端:

/**
 * RMI伺服器端<br/>
 * 
 * 
 * @author Joeson
 * @since 07/2014
 *
 */
public class ServerRMI
{

	public static void main(String[] args)
	{
		try
		{
			// 建立一個遠端物件
			HelloRMI hello = new HelloRMIImpl();
			// 本地主機上的遠端物件登錄檔Registry的例項,並指定埠為8080,這一步必不可少(Java預設埠是1099),必不可缺的一步,缺少登錄檔建立,則無法繫結物件到遠端登錄檔上
			LocateRegistry.createRegistry(8080);

			// 把遠端物件註冊到RMI註冊伺服器上,並命名為Hello, 繫結的URL標準格式為:rmi://host:port/name
			Naming.bind("rmi://localhost:8080/Hello", hello);
			System.out.println("RMI服務啟動...");

		} catch (RemoteException e)
		{
			System.out.println("建立遠端物件發生異常!");
		} catch (AlreadyBoundException e)
		{
			System.out.println("發生重複繫結物件異常!");
			e.printStackTrace();
		} catch (MalformedURLException e)
		{
			System.out.println("發生URL畸形異常!");
			e.printStackTrace();
		}
	}
}


RMI客戶端實現:

/**
 * RMI客戶端<br/>
 * 
 * @author Joeson
 * @since 07/2014
 *
 */
public class ClientRMI
{
	public static void main(String args[])
	{
		try
		{
			// 在RMI服務登錄檔中查詢名稱為Hello的物件,並呼叫其上的方法
			HelloRMI hello = (HelloRMI) Naming
					.lookup("rmi://localhost:8080/Hello");
			System.out.println(hello.hello());
		} catch (NotBoundException e)
		{
			e.printStackTrace();
		} catch (MalformedURLException e)
		{
			e.printStackTrace();
		} catch (RemoteException e)
		{
			e.printStackTrace();
		}
	}
}


執行結果


以上就是一個客戶端通過RMI方式呼叫伺服器端的是實現,實現分散式系統呼叫,而RMI的底層的真正實現就在於反射機制、序列化、反序列化和Socket程式設計,客戶端並不需要提供具體的實現,而是通過介面的方式與伺服器端的具體實現進行互動,呼叫伺服器端具體的實現,實現客戶端想要的效果,這就是分散式系統的業務處理模型了