日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

系统间通信2:通信管理与远程方法调用RMI

發(fā)布時(shí)間:2025/3/15 windows 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 系统间通信2:通信管理与远程方法调用RMI 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文引用 : https://yinwj.blog.csdn.net/article/details/49120813

RMI : Remote Method Invocation,遠(yuǎn)程方法調(diào)用
RPC : Remote Procedure Call Protocol, 遠(yuǎn)程過程調(diào)用協(xié)議
ESB : Enterprise Service Bus, 企業(yè)服務(wù)總線
SOA : Service-Oriented Architecture, 面向服務(wù)的架構(gòu)

1. 概述

在這個(gè)章節(jié)我將通過對RMI的詳細(xì)介紹,引出一個(gè)重要的系統(tǒng)間通信的管理規(guī)范RPC,并且繼續(xù)討論一些RPC的實(shí)現(xiàn);再通過分析PRC的技術(shù)特點(diǎn),引出另一種系統(tǒng)間通信的管理規(guī)范ESB,并介紹ESB的一些具體實(shí)現(xiàn)。最后我們介紹SOA:面向服務(wù)的軟件架構(gòu)。

2. RMI基本使用

RMI(Remote Method Invocation,遠(yuǎn)程方法調(diào)用),是JAVA早在JDK 1.1中提供的JVM與JVM之間進(jìn)行 對象方法調(diào)用的技術(shù)框架的實(shí)現(xiàn)(在JDK的后續(xù)版本中,又進(jìn)行了改進(jìn))。通過RMI技術(shù),某一個(gè)本地的JVM可以調(diào)用存在于另外一個(gè)JVM中的對象方法,就好像它僅僅是在調(diào)用本地JVM中某個(gè)對象方法一樣。例如RMI客戶端中的如下調(diào)用:

List< UserInfo > users = remoteServiceInterface.queryAllUserinfo();

看似remoteServiceInterface對象和普通的對象沒有區(qū)別,但實(shí)際上remoteServiceInterface對象的具體方法實(shí)現(xiàn)卻不在本地的JVM中,而是在某個(gè)遠(yuǎn)程的JVM中(這個(gè)遠(yuǎn)程的JVM可以是RMI客戶端同屬于一臺(tái)物理機(jī),也可以屬于不同的物理機(jī))

1.1 RMI使用場景

RMI是基于JAVA語言的,也就是說在RMI技術(shù)框架的描述中,只有Server端使用的是JAVA語言并且Client端也是用的JAVA語言,才能使用RMI技術(shù)(目前在codeproject.com中有一個(gè)開源項(xiàng)目名字叫做“RMI for C++”,可以實(shí)現(xiàn)JAVA To C++的RMI調(diào)用。但是這是一個(gè)第三方的實(shí)現(xiàn),并不是java的標(biāo)準(zhǔn)RMI框架定義,所以并不在我們的討論范圍中)。

RMI適用于兩個(gè)系統(tǒng)都主要使用JAVA語言進(jìn)行構(gòu)造,不需要考慮跨語言支持的情況。并且對兩個(gè)JAVA系統(tǒng)的通訊速度有要求的情況。

RMI 是一個(gè)良好的、特殊的RPC實(shí)現(xiàn):使用JRMP協(xié)議承載數(shù)據(jù)描述,可以使用BIO和NIO兩種IO通信模型。

1.2 RMI框架的基本組成

雖然RMI早在JDK.1.1版本中就開放了。但是在JDK1.5的版本中RMI又進(jìn)行改進(jìn)。所以我們后續(xù)的代碼示例和原理講解都基于最新的RMI框架特性。

要定義和使用一套基于RMI框架工作的系統(tǒng),您至少需要做一下幾個(gè)工作:

  • 定義RMI Remote接口
  • 實(shí)現(xiàn)這個(gè)RMI Remote接口
  • 生成Stub(樁)和Skeleton(骨架)。這一步的具體操作視不同的JDK版本而有所不同(例如JDK1.5后,Skeleton不需要手動(dòng));“RMI注冊表”的工作方式也會(huì)影響“Stub是否需要命令行生成”這個(gè)問題。
  • 向“RMI注冊表”注冊在第2步我們實(shí)現(xiàn)的RMI Remote接口。
  • 創(chuàng)建一個(gè)Remote客戶端,通過java“命名服務(wù)”在“RMI注冊表”所在的IP:PORT尋找注冊好的RMI服務(wù)。
  • Remote客戶端向調(diào)用存在于本地JVM中對象那樣,調(diào)用存在于遠(yuǎn)程JVM上的RMI接口。
  • 下圖描述了上述幾個(gè)概念名稱間的關(guān)系,呈現(xiàn)了JDK.5中RMI框架其中一種運(yùn)行方式(注意,是其中一種工作方式。也就是說RMI框架不一定都是這種運(yùn)行方式,后文中我們還將描述另外一種RMI的工作方式):

    1.3 RMI示例代碼

    在這個(gè)代碼中,我們將使用“本地RMI注冊表”(LocateRegistry),讓RMI服務(wù)的具體提供者和RMI注冊表工作在同一個(gè)JVM上,向您介紹最基本的RMI服務(wù)的定義、編寫、注冊和調(diào)用過程:

    首先我們必須定義RMI 服務(wù)接口,代碼如下:

    package testRMI;import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List;import testRMI.entity.UserInfo;public interface RemoteServiceInterface extends Remote {/*** 這個(gè)RMI接口負(fù)責(zé)查詢目前已經(jīng)注冊的所有用戶信息*/public List<UserInfo> queryAllUserinfo() throws RemoteException; }

    很簡單的代碼,應(yīng)該不用多解釋什么了。這個(gè)定義的接口方法如果放在某個(gè)業(yè)務(wù)系統(tǒng)A中,您可以理解是查詢這個(gè)系統(tǒng)A中所有可用的用戶資料。注意這個(gè)接口所繼承的java.rmi.Remote接口,是“RMI服務(wù)接口”定義的特點(diǎn)。

    那么有接口定義了,自然就要實(shí)現(xiàn)這個(gè)接口:

    package testRMI;import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.List;import testRMI.entity.UserInfo;/*** RMI 服務(wù)接口RemoteServiceInterface的具體實(shí)現(xiàn)<br>* 請注意這里繼承的是UnicastRemoteObject父類。* 繼承于這個(gè)父類,表示這個(gè)Remote Object是“存在于本地”的RMI服務(wù)實(shí)現(xiàn)* (這句話后文會(huì)解釋)* @author yinwenjie**/ public class RemoteUnicastServiceImpl extends UnicastRemoteObject implements RemoteServiceInterface {/*** 注意Remote Object沒有默認(rèn)構(gòu)造函數(shù)* @throws RemoteException*/protected RemoteUnicastServiceImpl() throws RemoteException {super();}private static final long serialVersionUID = 6797720945876437472L;/* (non-Javadoc)* @see testRMI.RemoteServiceInterface#queryAllUserinfo()*/@Overridepublic List<UserInfo> queryAllUserinfo() throws RemoteException {List<UserInfo> users = new ArrayList<UserInfo>();UserInfo user1 = new UserInfo();user1.setUserAge(21);user1.setUserDesc("userDesc1");user1.setUserName("userName1");user1.setUserSex(true);users.add(user1);UserInfo user2 = new UserInfo();user2.setUserAge(21);user2.setUserDesc("userDesc2");user2.setUserName("userName2");user2.setUserSex(false);users.add(user2);return users;} }

    還有我們定義的Userinfo信息,就是一個(gè)普通的POJO對象:

    package testRMI.entity;import java.io.Serializable; import java.rmi.RemoteException;public class UserInfo implements Serializable {/*** */private static final long serialVersionUID = -377525163661420263L;private String userName;private String userDesc;private Integer userAge;private Boolean userSex;public UserInfo() throws RemoteException {}/*** @return the userName*/public String getUserName() {return userName;}/*** @param userName the userName to set*/public void setUserName(String userName) {this.userName = userName;}/*** @return the userDesc*/public String getUserDesc() {return userDesc;}/*** @param userDesc the userDesc to set*/public void setUserDesc(String userDesc) {this.userDesc = userDesc;}/*** @return the userAge*/public Integer getUserAge() {return userAge;}/*** @param userAge the userAge to set*/public void setUserAge(Integer userAge) {this.userAge = userAge;}/*** @return the userSex*/public Boolean getUserSex() {return userSex;}/*** @param userSex the userSex to set*/public void setUserSex(Boolean userSex) {this.userSex = userSex;} }

    RMI Server 的接口定義和RMI Server的實(shí)現(xiàn)都有了,那么編寫代碼的最后一步是**將這個(gè)RMI Server注冊到“RMI 注冊表”中運(yùn)行。這樣 RMI的客戶端就可以調(diào)用這個(gè) RMI Server了。**下面的代碼是將RMI Server注冊到“本地RMI 注冊表”中:

    package testRMI;import java.rmi.Naming; import java.rmi.registry.LocateRegistry;public class RemoteUnicastMain {public static void main(String[] args) throws Exception {/** Locate registry,您可以理解成RMI服務(wù)注冊表,或者是RMI服務(wù)位置倉庫。* 主要的作用是維護(hù)一個(gè)“可以正常提供RMI具體服務(wù)的所在位置”。* 每一個(gè)具體的RMI服務(wù)提供者,都會(huì)講自己的Stub注冊到Locate registry中,以表示自己“可以提供服務(wù)”* * 有兩種方式可以管理Locate registry,一種是通過操作系統(tǒng)的命令行啟動(dòng)注冊表;* 另一種是在代碼中使用LocateRegistry類。* * LocateRegistry類中有一個(gè)createRegistry方法,可以在這臺(tái)物理機(jī)上創(chuàng)建一個(gè)“本地RMI注冊表”* */LocateRegistry.createRegistry(1099);// 以下是向LocateRegistry注冊(綁定/重綁定)RMI Server實(shí)現(xiàn)。RemoteUnicastServiceImpl remoteService = new RemoteUnicastServiceImpl();// 通過java 名字服務(wù)技術(shù),可以講具體的RMI Server實(shí)現(xiàn)綁定一個(gè)訪問路徑。注冊到LocateRegistry中Naming.rebind("rmi://127.0.0.1:1099/queryAllUserinfo", remoteService);/** 在“已經(jīng)擁有某個(gè)可訪問的遠(yuǎn)程RMI注冊表”的情況下。* 下面這句代碼就是向遠(yuǎn)程注冊表注冊RMI Server,* 當(dāng)然遠(yuǎn)程RMI注冊表的JVM-classpath中一定要有這個(gè)Server的Stub存在* * (運(yùn)行在另外一個(gè)JVM上的RMI注冊表,可能是同一臺(tái)物理機(jī)也可能不是同一臺(tái)物理機(jī))* Naming.rebind("rmi://192.168.61.1:1099/queryAllUserinfo", remoteService);* */} }

    這樣我們后續(xù)編寫的Client端就可以調(diào)用這個(gè)RMI Server了。下面的代碼是RMI Client的代碼:

    package testRMI;import java.rmi.Naming; import java.util.List;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.BasicConfigurator;import testRMI.entity.UserInfo;/*** 客戶端調(diào)用RMI測試* @author yinwenjie**/ public class RemoteClient {static {BasicConfigurator.configure();}/*** 日志*/private static final Log LOGGER = LogFactory.getLog(RemoteClient.class);public static void main(String[] args) throws Exception {// 您看,這里使用的是java名稱服務(wù)技術(shù)進(jìn)行的RMI接口查找。RemoteServiceInterface remoteServiceInterface = (RemoteServiceInterface)Naming.lookup("rmi://192.168.61.1/queryAllUserinfo");List<UserInfo> users = remoteServiceInterface.queryAllUserinfo();RemoteClient.LOGGER.info("users.size() = " +users.size());} }

    那么怎么來運(yùn)行這段代碼呢?如果您使用的是eclipse編寫了您第一個(gè)RMI Server和RMI Client,并且您使用的是“本地RMI 注冊表”。那么您不需要做任何的配置、腳本指定等工作(包括不需要專門設(shè)置JRE權(quán)限、不需要專門指定classpath、不需要專門生成Stub和Skeleton),就可以看到RMI的運(yùn)行和調(diào)用效果了:

    下圖為RemoteUnicastMain的效果RMI 服務(wù)注冊和執(zhí)行效果:

    可以看到,RemoteUnicastMain中的代碼執(zhí)行完成后整個(gè)應(yīng)用程序沒有退出。如下圖:

    這是因?yàn)檫@個(gè)應(yīng)用程序要承擔(dān)“真實(shí)的RMI Server實(shí)現(xiàn)”的服務(wù)調(diào)用。如果它退出,RMI 注冊表就無法請求真實(shí)的服務(wù)實(shí)現(xiàn)了
    我們再來看下圖,RemoteClient調(diào)用RMI 服務(wù)的效果:

    很明顯控制臺(tái)將返回:

    0 [main] INFO testRMI.RemoteClient - users.size() = 2

    3. JAVA RMI 原理

    通過上面的兩組代碼,我們大概知道了RMI框架是如何使用的。下面我們來講解一下RMI的基本原理。

    3.1 Registry和Stub、Skeleton的關(guān)系

    • 一定要說明,在RMI Client實(shí)施正式的RMI調(diào)用前,它必須通過LocateRegistry或者Naming方式到RMI注冊表尋找要調(diào)用的RMI注冊信息。找到RMI事務(wù)注冊信息后,Client會(huì)從RMI注冊表獲取這個(gè)RMI Remote Service的Stub信息。這個(gè)過程成功后,RMI Client才能開始正式的調(diào)用過程。

    • 另外要說明的是RMI Client正式調(diào)用過程,也不是由RMI Client直接訪問Remote Service,而是由客戶端獲取的Stub作為RMI Client的代理訪問Remote Service的代理Skeleton,如上圖所示的順序。也就是說真實(shí)的請求調(diào)用是在Stub-Skeleton之間進(jìn)行的。

    • Registry并不參與具體的Stub-Skeleton的調(diào)用過程,只負(fù)責(zé)記錄“哪個(gè)服務(wù)名”使用哪一個(gè)Stub,并在Remote Client詢問它時(shí)將這個(gè)Stub拿給Client

    3.2 Remote-Service線程管理

    在上文中的演示我們看到了RemoteRegistryUnicastMain處理請求時(shí),使用了線程池。這是JDK1.5到JDK1.6+版本中RMI框架的做的一個(gè)改進(jìn)。包括JDK1.5在內(nèi),之前的版本都采用新建線程的方式來處理請求;在JDK1.6版本之后,改用了線程池,并且線程池的大小是可以調(diào)整的:

    • sun.rmi.transport.tcp.maxConnectionThreads:連接池的大小,默認(rèn)為無限制。無限的大小肯定是有問題,按照Linux單進(jìn)程可打開的最大文件數(shù)限制,建議的設(shè)置值為65535(生產(chǎn)環(huán)境)。如果同一時(shí)間連接池中的線程數(shù)量達(dá)到了最大值,那么后續(xù)的Client請求將會(huì)報(bào)錯(cuò)。測試環(huán)境/開發(fā)環(huán)境是否設(shè)置這個(gè)值,就沒有那么重要了。

    • sun.rmi.transport.tcp.threadKeepAliveTime:如果當(dāng)線程池中有閑置的線程資源的話,那么這個(gè)閑置線程資源多久被注銷(單位毫秒),默認(rèn)的設(shè)置是1分鐘。

    如果您使用的是linux或者window的命令控制臺(tái)執(zhí)行的話,您可以通過類似如下語句進(jìn)行參數(shù)設(shè)置:

    java -Dsun.rmi.transport.tcp.maxConnectionThreads=2 -Dsun.rmi.transport.tcp.threadKeepAliveTime=1000 testRMI.RemoteRegistryUnicastMain

    3.3 Registry和Naming

    Registry和Naming都可以進(jìn)行RMI服務(wù)的bind/rebind/unbind,都可以用lookup方法查詢RMI服務(wù)。Naming實(shí)際上是對Registry的封裝。使用完整的URL方式對已注冊的服務(wù)名進(jìn)行查找。

    3.4 UnicastRemoteObject和Activatable

    在JDK1.2版本中,由Ann Wollrath執(zhí)筆加入了一種新的RMI工作方式。即通過RMI“活化”模式,將Remote Service的真實(shí)提供者移植到RMI Registry注冊表所在的JVM上。要使用這種工作模式的Remote Service實(shí)現(xiàn)不再繼承UnicastRemoteObject類,而需要繼承Activatable類(其他的業(yè)務(wù)代碼不需要改變)

    4. RMI:一種特殊的RPC服務(wù)實(shí)現(xiàn)

    之所以介紹RMI,是因?yàn)橐ㄟ^介紹RMI引出一種重要的系統(tǒng)間通訊管理框架RPC.

    總結(jié)

    以上是生活随笔為你收集整理的系统间通信2:通信管理与远程方法调用RMI的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲免费激情视频 | 无码人妻丰满熟妇区五十路百度 | 久久亚洲精品石原莉奈 | 桃花久久 | 性色视频在线 | 日韩偷拍一区 | 蜜臀久久99精品久久久久久 | 久久免费成人 | 在线观看国产 | free黑人多人性派对hd | 岛国av免费在线 | 亚洲1024 | 日韩v片| 九色影视 | 欧美双性人妖o0 | 日韩美女少妇 | 播播激情网 | 红猫大本营在线观看的 | 娇妻高潮浓精白浆xxⅹ | 亚洲欧美色图片 | 黄色欧美在线观看 | 亚洲国产欧洲 | 尤物网站在线观看 | av网站在线免费播放 | 亚洲激情国产 | 乳揉みま痴汉4在线播放 | 91精品视频免费观看 | 亚洲免费观看高清完整版在线 | 国产精品无码一区二区三区在线看 | 精品免费视频 | 少妇精品一区 | 亚洲免费小视频 | 欧美午夜在线视频 | 中文字幕精品一区久久久久 | 国产福利av | 杏导航aⅴ福利网站 | 巨胸喷奶水www久久久免费动漫 | 日本黄色大片免费看 | 无码国精品一区二区免费蜜桃 | 成人激情视频在线观看 | 亚洲天堂中文字幕在线观看 | 在线免费观看一级片 | 中文字幕日韩在线观看 | 中文字幕有码无码人妻av蜜桃 | 日韩毛片在线视频 | 天堂网在线最新版www中文网 | 99久久人妻精品免费二区 | 热久久久久 | 黑人性xxx | 欧美超碰在线 | 天天射天天舔 | 国产一区二区三区免费看 | sese亚洲 | 亚洲精品国产suv | 日本xxxxwwwww| 精品久久人妻av中文字幕 | 亚洲自拍偷拍色图 | 国产1区2区3区4区 | 激情拍拍 | 一个人在线免费观看www | av黄色大片| 多毛的亚洲人毛茸茸 | 国产又粗又猛又黄又爽无遮挡 | 国产在线欧美在线 | 在线观看a视频 | 久久中文字幕电影 | www国产在线观看 | 成人免费在线播放 | 一起草最新网址 | 色牛av| 久久这里 | a级片一级片 | 国产中文字幕一区 | 一本久久道 | 日韩午夜剧场 | 中文精品一区 | 操bbbbb| 日吊视频 | 日本中文字幕高清 | 水蜜桃影库 | 色噜噜一区二区 | 久久久蜜桃 | 夫妻露脸自拍[30p] | 香蕉狠狠爱视频 | 精品成人av一区二区在线播放 | 国产做爰xxxⅹ久久久精华液 | 少妇被粗大猛进进出出s小说 | 国产香蕉9| 亚洲av无码国产精品久久久久 | 色婷婷国产精品视频 | 亚洲成人中文 | 少妇紧身牛仔裤裤啪啪 | 国产精品vip | 国产高清第一页 | 精品国产理论 | 秋霞欧洲| 午夜美女网站 | 免费av看片 | 色偷偷av|