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