RMI (Remote Method Invocation,遠(yuǎn)程方法調(diào)用)是JAVA一組擁護(hù)開(kāi)發(fā)分布式應(yīng)用程序的API,用于不同虛擬機(jī)間的通信,核心是遠(yuǎn)程對(duì)象
RMI通信模型:

1、客戶(hù)端調(diào)用輔助對(duì)象stub上方法
2、stub對(duì)調(diào)用信息(變量、方法)打包,網(wǎng)絡(luò)發(fā)給服務(wù)端輔助對(duì)象
3、(1.2前)skeleton將stub送來(lái)的信息解包,找到被調(diào)方法的對(duì)象及本身
4、調(diào)用服務(wù)端對(duì)象上的方法,將結(jié)果返回給skeleton、打包、給stub
5、stub解包,返給客戶(hù)端對(duì)象,獲取返回值
可以把stub理解為本地的一個(gè)代理對(duì)象,客戶(hù)端不知道server的存在,
數(shù)據(jù)傳遞問(wèn)題:
分布式系統(tǒng)、不同內(nèi)存空間,虛擬機(jī)A對(duì)象的引用對(duì)于虛擬機(jī)B沒(méi)有意義
解決方案一:引用傳遞更改為值傳遞
將對(duì)象序列化為字節(jié),使用字節(jié)副本在客戶(hù)端、服務(wù)器間傳遞,一個(gè)虛擬機(jī)對(duì)該值的修改不影響其他主機(jī)的數(shù)據(jù),問(wèn)題:對(duì)象嵌套引用造成序列化嵌套,數(shù)據(jù)量激增
能不能被序列化要滿(mǎn)足下面任一條件:1、java基本類(lèi)型,2、實(shí)現(xiàn)Serializable接口,3、容器類(lèi)中的對(duì)象可以序列化,容器也可以序列化,4、子類(lèi)可序列化,其可序列化
當(dāng)遠(yuǎn)程主機(jī)調(diào)用本地主機(jī)方法時(shí),通過(guò)本地主機(jī)查詢(xún)引用對(duì)應(yīng)的對(duì)象;對(duì)象共享、一變都收影響
RMI參數(shù)傳遞和結(jié)果返回的三種機(jī)制:
1、簡(jiǎn)單類(lèi)型:按值傳遞、傳遞數(shù)據(jù)拷貝;2、(實(shí)現(xiàn)了Remote接口的)遠(yuǎn)程對(duì)象引用、以遠(yuǎn)程對(duì)象的引用傳遞;3、(未實(shí)現(xiàn)Remote接口)遠(yuǎn)程對(duì)象引用,按值傳遞,通過(guò)序列化傳遞副本
遠(yuǎn)程對(duì)象的發(fā)現(xiàn)問(wèn)題:
調(diào)用遠(yuǎn)程對(duì)象方法前需遠(yuǎn)程對(duì)象的引用,如何獲取吶?首先咱們把“將遠(yuǎn)程對(duì)象的發(fā)現(xiàn)”類(lèi)比于IP地址的發(fā)現(xiàn)
實(shí)際生活中網(wǎng)絡(luò)通過(guò)IP地址來(lái)定位網(wǎng)站,這有一個(gè)映射的過(guò)程,在DNS(Domain Name System)域名系統(tǒng)中通過(guò)域名來(lái)查找對(duì)應(yīng)的IP地址來(lái)訪(fǎng)問(wèn)服務(wù)器,這里IP相當(dāng)于遠(yuǎn)程對(duì)象的引用,DNS相當(dāng)于一個(gè)注冊(cè)表Registry,域名在RMI中相當(dāng)于遠(yuǎn)程對(duì)象的標(biāo)識(shí)符,客戶(hù)端通過(guò)提供遠(yuǎn)程對(duì)象的標(biāo)識(shí)符訪(fǎng)問(wèn)注冊(cè)表、得到遠(yuǎn)程對(duì)象的引用;標(biāo)識(shí)符:
名稱(chēng)是URL形式的,類(lèi)似于http的URL,schema是rmi,rmi://host:port/name,host注冊(cè)表運(yùn)行的注解,port接收調(diào)用的端口,name是標(biāo)識(shí)對(duì)象的簡(jiǎn)單名稱(chēng),主機(jī)和端口可選、依次默認(rèn)本地、1099
編程實(shí)現(xiàn):
服務(wù)器端:
遠(yuǎn)程對(duì)象:實(shí)現(xiàn)java.rmi.Remote接口或繼承java.rmi.Remote接口的接口
在遠(yuǎn)程接口中聲明的方法才能被遠(yuǎn)程調(diào)用
注意事項(xiàng):
1、子接口中方法必須拋出java.rmi.RemoteException異常(使用RMI時(shí)可能拋出的大多數(shù)異常的父類(lèi))
2、子接口的實(shí)現(xiàn)類(lèi)直接、間接繼承java.rmi.server.UnicastRemoteObject(提供了很多支持RMI的方法,這些方法可以通過(guò)JRMP協(xié)議導(dǎo)出一個(gè)遠(yuǎn)程對(duì)象的引用并動(dòng)態(tài)代理構(gòu)建可以和遠(yuǎn)程對(duì)象交互的stub對(duì)象)
public interface UserHandler extends Remote { String getUserName(int id) throws RemoteException; }
實(shí)體類(lèi):序列化、serialVersionUID(后面客戶(hù)端對(duì)應(yīng)上)
public class User implements Serializable { // 該字段必須存在 private static final long serialVersionUID = 42L; // setter和getter可以沒(méi)有 String name; int id; public User(String name, int id) { this.name = name; this.id = id; } }
實(shí)現(xiàn)類(lèi):
public class UserHandlerImpl extends UnicastRemoteObject implements UserHandler { // 該構(gòu)造期必須存在,因?yàn)榧^承了UnicastRemoteObject類(lèi),其構(gòu)造器要拋出RemoteException public UserHandlerImpl() throws RemoteException { super(); } @Override public String getUserName(int id) throws RemoteException { return "開(kāi)掛的人生"; } }
運(yùn)行遠(yuǎn)程對(duì)象:
UserHandler userHandler = null; userHandler = new UserHandlerImpl(); Naming.rebind("user", userHandler);//通過(guò)名稱(chēng)映射到該遠(yuǎn)程對(duì)象的引用,客戶(hù)端通過(guò)該名稱(chēng)獲取該遠(yuǎn)程對(duì)象的引用。
注冊(cè)表:
運(yùn)行exe
JAVA_HOME下bin目錄下有一個(gè)rmiregistry.exe程序,在你的程序的classpath下運(yùn)行該程序
編程運(yùn)行
通過(guò)java.rmi.registry包中的Registry接口和以及其實(shí)現(xiàn)類(lèi)LocateRegistry來(lái)完成的
客戶(hù)端:
UserHandler handler = (UserHandler) Naming.lookup("user");//通過(guò)名稱(chēng)獲取遠(yuǎn)程對(duì)象引用 int count = handler.getUserCount(); String name = handler.getUserName(1);
小結(jié):
不知道怎么就學(xué)到這了?大概是序列化吧,時(shí)間緊任務(wù)重,這塊還是需要寫(xiě)個(gè)小結(jié)的,RMI用于分布式方法調(diào)用,借助于remote遠(yuǎn)程調(diào)用,過(guò)程中存在一些隱患拋出異常,分布式中你去找哪個(gè)戶(hù)下的哪個(gè)窗吶?通過(guò)名字還有serialVersionUID在注冊(cè)表里面找,想起了Dubbo、springCloud
有錯(cuò)誤之處歡迎指出,共同交流、一起進(jìn)步、為中國(guó)造芯片!
百科渡一下
注:DNS:因特網(wǎng)的一項(xiàng)核心服務(wù),它作為將域名和IP地址相互映射的一個(gè)分布式數(shù)據(jù)庫(kù),能夠使人更方便的訪(fǎng)問(wèn)互聯(lián)網(wǎng),而不用去記住能夠被機(jī)器直接讀取的IP數(shù)串【源】
JRMP:java remote method protocol,Java遠(yuǎn)程方法協(xié)議,JAVA特有的基于流的協(xié)議