1. 程式人生 > >Java RMI詳解

Java RMI詳解

RMI:遠端方法呼叫(Remote Method Invocation)。能夠讓在某個java虛擬機器上的物件像呼叫本地物件一樣呼叫另一個java 虛擬機器中的物件上的方法。

RMI遠端呼叫步驟:

1,客戶物件呼叫客戶端輔助物件上的方法

2,客戶端輔助物件打包呼叫資訊(變數,方法名),通過網路傳送給服務端輔助物件

3,服務端輔助物件將客戶端輔助物件傳送來的資訊解包,找出真正被呼叫的方法以及該方法所在物件

4,呼叫真正服務物件上的真正方法,並將結果返回給服務端輔助物件

5,服務端輔助物件將結果打包,傳送給客戶端輔助物件

6,客戶端輔助物件將返回值解包,返回給客戶物件

7,客戶物件獲得返回值

對於客戶物件來說,步驟2-6是完全透明的

搭建一個RMI服務的過程分為以下7步;

1,建立遠端方法介面,該介面必須繼承自Remote介面

Remote 介面是一個標識介面,用於標識所包含的方法可以從非本地虛擬機器上呼叫的介面,Remote介面本身不包含任何方法

package server;

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

public interface Hello extends Remote {
	public String sayHello(String name) throws RemoteException;
}

由於遠端方法呼叫的本質依然是網路通訊,只不過隱藏了底層實現,網路通訊是經常會出現異常的,所以介面的所有方法都必須丟擲RemoteException

以說明該方法是有風險的

2,建立遠端方法介面實現類:

UnicastRemoteObject類的建構函式丟擲了RemoteException,故其繼承類不能使用預設建構函式,繼承類的建構函式必須也丟擲RemoteException

由於方法引數返回值最終都將在網路上傳輸,故必須是可序列化的

package server;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements Hello {
	private static final long serialVersionUID = -271947229644133464L;

	public HelloImpl() throws RemoteException{
		super();
	}

	public String sayHello(String name) throws RemoteException {
		return "Hello,"+name;
	}
}

3,利用java自帶rmic工具生成sutb存根類(jdk1.5.0_15/bin/rmic)

jdk1.2以後的RMI可以通過反射API可以直接將請求傳送給真實類,所以不需要skeleton類了

sutb存根為遠端方法類在本地的代理,是在服務端程式碼的基礎上生成的,需要HelloImpl.class檔案,由於HelloImpl繼承了Hello介面,故Hello.class檔案也是不可少的

Test

- - server

- - - - Hello.class

- - - - HelloImpl.class

方式一:

[[email protected] Test]$ cd /home/name/Test/
[[email protected] Test]$ rmic server.HelloImpl

方式二:

[[email protected] Test]$ rmic -classpath /home/name/Test server.HelloImpl

 執行成功後將會生成HelloImpl_Stub.class檔案

4,啟動RMI註冊服務(jdk1.5.0_15/bin/rmiregistry)

方式一:後臺啟動rmiregistry服務

[[email protected] jdk]$ jdk1.5.0_15/bin/rmiregistry 12312 &
[1] 22720
[[email protected] jdk]$ ps -ef|grep rmiregistry
name    22720 13763  0 16:43 pts/3    00:00:00 jdk1.5.0_15/bin/rmiregistry 12312
name    22737 13763  0 16:43 pts/3    00:00:00 grep rmiregistry

如果不帶具體埠號,則預設為1099

方式二:人工建立rmiregistry服務,需要在程式碼中新增:

LocateRegistry.createRegistry(12312);

5,編寫服務端程式碼

package server;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class HelloServer {
	public static void main(String[] args) {
		try{
			Hello h = new HelloImpl();
			
			//建立並匯出接受指定port請求的本地主機上的Registry例項。
			//LocateRegistry.createRegistry(12312);
			
			/**	Naming 類提供在物件登錄檔中儲存和獲得遠端對遠端物件引用的方法
			 *  Naming 類的每個方法都可將某個名稱作為其一個引數,
			 *  該名稱是使用以下形式的 URL 格式(沒有 scheme 元件)的 java.lang.String:
			 *  //host:port/name
			 *  host:登錄檔所在的主機(遠端或本地),省略則預設為本地主機
			 *  port:是登錄檔接受呼叫的埠號,省略則預設為1099,RMI登錄檔registry使用的著名埠
			 *  name:是未經登錄檔解釋的簡單字串
			 */
			//Naming.bind("//host:port/name", h);
			Naming.bind("rmi://192.168.58.164:12312/Hello", h);
			System.out.println("HelloServer啟動成功");
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

先建立登錄檔,然後才能在登錄檔中儲存遠端物件資訊

6,執行服務端(58.164):

Test

- - server

- - - - Hello.class

- - - - HelloImpl.class

- - - - HelloServer.class

[[email protected] ~]$ java server.HelloServer
HelloServer啟動成功

當然/home/name/Test一定要在系統CLASSPATH中,否則會報找不到相應的.class檔案

7,編寫客戶端程式碼

package client;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import server.Hello;

public class HelloClient {
	public static void main(String[] args) {
		try {
			Hello h = (Hello)Naming.lookup("rmi://192.168.58.164:12312/Hello");
			System.out.println(h.sayHello("zx"));
		} catch (MalformedURLException e) {
			System.out.println("url格式異常");
		} catch (RemoteException e) {
			System.out.println("建立物件異常");
			e.printStackTrace();
		} catch (NotBoundException e) {
			System.out.println("物件未繫結");
		}
	}
}

8,執行客戶端(58.163):

Test

- - client

- - - - HelloClient.class

- - server

- - - - Hello.class

- - - - HelloImpl_Stub.class//服務端生成的存根檔案

[[email protected] client]$ java client.HelloClient
Hello,zx

同伺服器端,/home/name/Test一定要在系統CLASSPATH中

PS:

1,客戶端所在服務和服務端所在的伺服器網路一定要通(一開始浪費了很多時間,最後才發現是網路不通)

2,所有程式碼在jdk1.5.0_15,Linux伺服器上除錯通過

3,如果java命令執行提示找不到類檔案,則為CLASSPATH配置問題

[[email protected] ~]$ vi .bash_profile 
JAVA_HOME=/home/name/jdk/jdk1.5.0_15
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:/home/name/Test
export CLASSPATH

JAVA_HOME為jdk的根目錄

PATH為java工具類路徑(java,javac,rmic等)

CLASSPATH為java .class檔案的存放路徑,使用java命令執行.class檔案時即會在該引數配置的路徑下尋找相應檔案

java RMI的缺點:

1,從程式碼中也可以看到,程式碼依賴於ip與埠

2,RMI依賴於Java遠端訊息交換協議JRMP(Java Remote Messaging Protocol),該協議為java定製,要求服務端與客戶端都為java編寫

相關推薦

布式架構基礎:Java RMI

RMI簡介 ​ Java RMI,即 遠端方法呼叫(Remote Method Invocation),一種用於實現遠端過程呼叫(RPC)(Remote procedure call)的Java API, 能直接傳輸序列化後的Java物件和分散式垃圾收集。它的

分散式架構基礎:Java RMI

GitHub: github.com/jayknoxqu/r… RMI簡介 ​ Java RMI,即 遠端方法呼叫(Remote Method Invocation),一種用於實現遠端過程呼叫(RPC)(Remote procedure call)的Java API, 能直接傳輸序列化後的Java物件和分

分散式架構基礎之Java RMI

RMI簡介 ​Java RMI或遠端方法呼叫是用於遠端過程呼叫的Java API,它可以直接傳輸序列化Java物件和分散式垃圾收集。它的實現依賴於Java虛擬機器(JVM),因此它只支援從一個JVM到另一個JVM的呼叫。   rmi的實現 (1) 直接使用Regist

Java RMI

RMI:遠端方法呼叫(Remote Method Invocation)。能夠讓在某個java虛擬機器上的物件像呼叫本地物件一樣呼叫另一個java 虛擬機器中的物件上的方法。 RMI遠端呼叫步驟: 1,客戶物件呼叫客戶端輔助物件上的方法 2,客戶端輔助物件打包呼叫資訊(變數

java final

inline mon 技術 但是 common src strac 都是 機制 final關鍵字 可用於聲明屬性、方法、和類 final類: final 類 不可被繼承,沒有子類,包括其中的方法默認都是final方法; final 類的方法不可被重寫,但是其中沒有被f

Java IO

amr mst 數據丟失 網上 ria break idc png 字符串 學習Java的同學註意了!!! 學習過程中遇到什麽問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:618528494 我們一起學Java! 初學Java,一直搞不懂Java裏

Java synchronized

ret 內置 etc 優先權 one lan string 作用域 靜態成員函數 轉自:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html 第一篇: 使用synchronized 在編寫一個

Java 反射

什麽 tco type 性能 bob 參數 bject 今天 erl   反射反射,程序員的快樂,今天你快樂了嗎?如果你不快樂,沒關系,接下來讓你快樂起來! 一、什麽是反射?  通過百度百科我們可以知道,Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬

Java代理

.get tle 理由 總結 ins 創建 set ota ble 一、概述   代理模式是Java常用的設計模式之一,實現代理模式要求代理類和委托類(被代理的類)具有相同的方法(提供相同的服務),代理類對象自身並不實現真正的核心邏輯,而是通過調用委托類對象的相關方法來處

spark2.x由淺入深深到底系列六之RDD java api

spark 大數據 javaapi 老湯 rdd package com.twq.javaapi.java7; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.

spark2.x由淺入深深到底系列六之RDD java api

老湯 spark 大數據 javaapi rdd 學習任何spark知識點之前請先正確理解spark,可以參考:正確理解spark本文詳細介紹了spark key-value類型的rdd java api一、key-value類型的RDD的創建方式1、sparkContext.parall

spark2.x由淺入深深到底系列六之RDD java api

spark 大數據 javaapi 老湯 rdd 學習spark任何的知識點之前,先對spark要有一個正確的理解,可以參考:正確理解spark本文對join相關的api做了一個解釋SparkConf conf = new SparkConf().setAppName("appName")

Java HashCode

popu 容器類 itl 基本上 映射 nat 程序設計語言 http 容器 一、為什麽要有Hash算法 Java中的集合有兩類,一類是List,一類是Set。List內的元素是有序的,元素可以重復。Set元素無序,但元素不可重復。要想保證元素不重復,兩個元素是否重復應該依

Java異常

ror 編寫 等於 title 操作系統 通過反射 異常類 原因 數組 一、Java異常概述 在Java中,所有的事件都能由類描述,Java中的異常就是由java.lang包下的異常類描述的。 Throwable(可拋出):異常類的最終父類,它有兩個子類,Error與Ex

Java BigDecimal,提供了豐富的四舍五入規則

字節 equals mat hashcode 字符 plain move man gnu java.math.BigDecimal類提供用於算術,刻度操作,舍入,比較,哈希算法和格式轉換操作。 toString()方法提供BigDecimal的規範表示。它使用戶可以完全控制

Java內部類

進行 system 創建 經典 生成 接口 為什麽 bsp 產生 可以將一個類的定義放在另一個類的定義內部,這就是內部類。 內部類是一個非常有用的特性但又比較難理解使用的特性(鄙人到現在都沒有怎麽使用過內部類,對內部類也只是略知一二)。 第一次見面

javaJFrame結構的分層

運行 容器 ava 背景色 jpanel new ima () 詳解 在這篇博文中,筆者會介紹JFrame窗口的分層。JFrame繼承自Frame,同JFrame、JDialog、JApplet都是重量級組件。如果不弄清楚Frame的分層結構,那麽在設置組件的某些特效的時候

Java菜單組件

組件 tcl 而是 ide 就會 npe awt div 鍵盤 在這篇文章中,筆者會介紹Java圖形界面編程中菜單組件的用法。關於菜單組件,因為java存在AWT編程和Swing編程,所以菜單組件也存在AWT菜單和Swing菜單。因為Swing組件使用的比較多,所以筆者的案

Java ClassLoad

method oda tor tst 語言 不同版本 -i tla 情況下 Java ClassLoad詳解 類加載器是 Java 語言的一個創新,也是 Java 語言流行的重要原因之一。它使得 Java 類可以被動態加載到 Java 虛擬機中並執行。類加載

java反射

編譯 imp 成員 參數類型 信息 執行方法 定義 所有 c++ 1.什麽是反射 反射是一種間接操作目標對象的機制,在程序程序運行時(動態)獲取或者設置對象自身的信息。只要給定類的名字,就可以通過反射獲取類的所有信息,接著便能調用它的任何一個方法和屬性。 Jav