- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- 詳解Java 中 RMI 的使用
RMI (Remote Method Invocation) 模型是一種分布式對象應用,使用 RMI 技術(shù)可以使一個(gè) JVM 中的對象,調用另一個(gè) JVM 中的對象方法并獲取調用結果。這里的另一個(gè) JVM 可以在同一臺計算機也可以是遠程計算機。因此,RMI 意味著(zhù)需要一個(gè) Server 端和一個(gè) Client 端。
Server 端通常會(huì )創(chuàng )建一個(gè)對象,并使之可以被遠程訪(fǎng)問(wèn)。
這個(gè)對象被稱(chēng)為遠程對象。Server 端需要注冊這個(gè)對象可以被 Client 遠程訪(fǎng)問(wèn)。
Client 端調用可以被遠程訪(fǎng)問(wèn)的對象上的方法,Client 端就可以和 Server 端進(jìn)行通信并相互傳遞信息。
說(shuō)到這里,是不是發(fā)現使用 RMI 在構建一個(gè)分布式應用時(shí)十分方便,它和 RPC 一樣可以實(shí)現分布式應用之間的互相通信,甚至和現在的微服務(wù)思想都十分類(lèi)似。
正所謂 “知其然知其所以然”,在開(kāi)始編寫(xiě) RMI 代碼之前,有必要了解一下 RMI 的工作原理,RMI 中 Client 端是和 Server 端是如何通信的呢?
下圖的可以幫助我們理解RMI 的工作流程。
從圖中可以看到,Client 端有一個(gè)被稱(chēng) Stub 的東西,有時(shí)也會(huì )被成為存根,它是 RMI Client 的代理對象,Stub 的主要功能是請求遠程方法時(shí)構造一個(gè)信息塊,RMI 協(xié)議會(huì )把這個(gè)信息塊發(fā)送給 Server 端。
這個(gè)信息塊由幾個(gè)部分組成:
既然 Client 端有一個(gè) Stub 可以構造信息塊發(fā)送給 Server 端,那么 Server 端必定會(huì )有一個(gè)接收這個(gè)信息快的對象,稱(chēng)為 Skeleton 。
它主要的工作是:
到這里,一次從 Client 端對 Server 端的調用結果就可以獲取到了。
通過(guò)上面的介紹,知道了 RMI 的概念以及 RMI 的工作原理,下面介紹 RMI 的開(kāi)發(fā)流程。
這里會(huì )通過(guò)一個(gè)場(chǎng)景進(jìn)行演示,假設 Client 端需要查詢(xún)用戶(hù)信息,而用戶(hù)信息存在于 Server 端,所以在 Server 端開(kāi)放了 RMI 協(xié)議接口供客戶(hù)端調用查詢(xún)。
Server 端主要是構建一個(gè)可以被傳輸的類(lèi) User,一個(gè)可以被遠程訪(fǎng)問(wèn)的類(lèi) UserService,同時(shí)這個(gè)對象要注冊到 RMI 開(kāi)放給客戶(hù)端使用。
1.定義服務(wù)器接口(需要繼承 Remote 類(lèi),方法需要拋出 RemoteException)。
package com.wdbyte.rmi.server; import java.rmi.Remote; import java.rmi.RemoteException; /** * RMI Server * * @author www.wdbyte.com * @date 2021/05/08 */ public interface UserService extends Remote { /** * 查找用戶(hù) * * @param userId * @return * @throws RemoteException */ User findUser(String userId) throws RemoteException; }
User 對象在步驟 3 中定義。
2.實(shí)現服務(wù)器接口(需要繼承 UnicastRemoteObject 類(lèi),實(shí)現定義的接口)。
package com.wdbyte.rmi.server; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; /** * @author www.wdbyte.com * @date 2021/05/08 */ public class UserServiceImpl extends UnicastRemoteObject implements UserService { protected UserServiceImpl() throws RemoteException { } @Override public User findUser(String userId) throws RemoteException { // 加載在查詢(xún) if ("00001".equals(userId)) { User user = new User(); user.setName("金庸"); user.setAge(100); user.setSkill("寫(xiě)作"); return user; } throw new RemoteException("查無(wú)此人"); } }
3.定義傳輸的對象,傳輸的對象需要實(shí)現序列化(Serializable)接口。
需要傳輸的類(lèi)一定要實(shí)現序列化接口,不然傳輸時(shí)會(huì )報錯。IDEA 中如何生成 serialVersionUID,在文章末尾也附上了簡(jiǎn)單教程。
package com.wdbyte.rmi.server; import java.io.Serializable; /** * * @author www.wdbyte.com * @date 2021/05/08 */ public class User implements Serializable { private static final long serialVersionUID = 6490921832856589236L; private String name; private Integer age; private String skill; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSkill() { return skill; } public void setSkill(String skill) { this.skill = skill; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", skill='" + skill + '\'' + '}'; } }
4.注冊( rmiregistry)遠程對象,并啟動(dòng)服務(wù)端程序。
服務(wù)端綁定了 UserService 對象作為遠程訪(fǎng)問(wèn)的對象,啟動(dòng)時(shí)端口設置為 1900。
package com.wdbyte.rmi.server; import java.rmi.Naming; import java.rmi.registry.LocateRegistry; /** * RMI Server 端 * * @author https://www.wdbyte.com * @date 2021/05/08 */ public class RmiServer { public static void main(String[] args) { try { UserService userService = new UserServiceImpl(); LocateRegistry.createRegistry(1900); Naming.rebind("rmi://localhost:1900/user", userService); System.out.println("start server,port is 1900"); } catch (Exception e) { e.printStackTrace(); } } }
相比 Server 端,Client 端就簡(jiǎn)單的多。直接引入可遠程訪(fǎng)問(wèn)和需要傳輸的類(lèi),通過(guò)端口和 Server 端綁定的地址,就可以發(fā)起一次調用。
package com.wdbyte.rmi.client; import java.rmi.Naming; import com.wdbyte.rmi.server.User; import com.wdbyte.rmi.server.UserService; /** * @author https://www.wdbyte.com * @date 2021/05/08 */ public class RmiClient { public static void main(String args[]) { User answer; String userId = "00001"; try { // lookup method to find reference of remote object UserService access = (UserService)Naming.lookup("rmi://localhost:1900/user"); answer = access.findUser(userId); System.out.println("query:" + userId); System.out.println("result:" + answer); } catch (Exception ae) { System.out.println(ae); } } }
啟動(dòng) Server 端。
start server,port is 1900
啟動(dòng) Client 端。
query:00001 result:User{name='金庸', age=100, skill='寫(xiě)作'}
如果 Client 端傳入不存在的 userId。
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: java.rmi.RemoteException: 查無(wú)此人
IDEA 中生成 serialVersionUID,打開(kāi)設置,如下圖所示勾選。
選中要生成 serialVersionUID 的類(lèi),按智能提示快捷鍵。
參考
[1]
到此這篇關(guān)于詳解Java 中 RMI 的使用的文章就介紹到這了,更多相關(guān)java RMI使用內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站