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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java分布式对象(RMI+部署使用RMI的程序)

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java分布式对象(RMI+部署使用RMI的程序) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【0】README

1)本文文字轉(zhuǎn)自 core java volume 2, 旨在學(xué)習(xí) java 分布式對(duì)象的相關(guān)知識(shí);
2) RMI 的實(shí)例程序?yàn)樵瓌?chuàng);
3) RMI部署步驟的測(cè)試用例,參見 http://blog.csdn.net/pacosonswjtu/article/details/50705258


【1】知識(shí)背景

1)每過一段時(shí)間, 程序員社區(qū)就開始考慮“無所不在的對(duì)象”作為所有問題的解決之道;
2) 當(dāng)一臺(tái)計(jì)算機(jī)上的某個(gè)對(duì)象需要調(diào)用另一臺(tái)計(jì)算機(jī)上的某個(gè)對(duì)象時(shí), 他就會(huì)發(fā)送一個(gè)包含這個(gè)請(qǐng)求的詳細(xì)信息的網(wǎng)絡(luò)消息;
3)一旦該遠(yuǎn)程對(duì)象得到了客戶端請(qǐng)求的東西, 就將他發(fā)送給 客戶端;
4)在本章,我們將聚焦在Java的分布式編程技術(shù)上,特別是用于兩個(gè)Java虛擬機(jī)(可以運(yùn)行在不同的計(jì)算機(jī)上)之間通信的遠(yuǎn)程方法調(diào)用(RMI)協(xié)議。
5)RMI: Remote Method Invocation == 遠(yuǎn)程方法調(diào)用協(xié)議;


【2】客戶與服務(wù)器的角色

1)所有分布式編程技術(shù)的基本思想都很簡(jiǎn)單:客戶計(jì)算機(jī)產(chǎn)生一個(gè)請(qǐng)求,然后將這個(gè)請(qǐng)求經(jīng)由網(wǎng)絡(luò)發(fā)送到服務(wù)器。服務(wù)器處理這個(gè)請(qǐng)求,并發(fā)送回一個(gè)針對(duì)該客戶端的響應(yīng),供客戶端進(jìn)行分析。圖11-1展示了這個(gè)過程。

2)problem+solution:

  • 2.1)problem:我們真正想要的是這樣一種機(jī)制,客戶端程序員以常規(guī)的方式進(jìn)行方法調(diào)用,而無需操心數(shù)據(jù)在網(wǎng)絡(luò)上傳輸或者解析響應(yīng)之類的問題。
  • 2.2)solution:解決的辦法是,在客戶端為遠(yuǎn)程對(duì)象安裝一個(gè)代理(proxy)。(干貨——引入代理的概念)

3)代理: 是位于客戶端虛擬機(jī)中的一個(gè)對(duì)象,它對(duì)于客戶端程序來說,看起來就像是要訪問的遠(yuǎn)程對(duì)象一樣??蛻粽{(diào)用此代理,進(jìn)行常規(guī)的方法調(diào)用。而客戶端代理負(fù)責(zé)與服務(wù)器進(jìn)行聯(lián)系。
4)problem+solution:

  • 4.1)problem:實(shí)現(xiàn)服務(wù)的程序員也不希望因與客戶端之間的通信而被絆住。
  • 4.2)solution:解決方法是在服務(wù)器端安裝第二個(gè)代理對(duì)象。該服務(wù)器代理與客戶端代理進(jìn)行通信,并且它將以常規(guī)方式調(diào)用服務(wù)器對(duì)象上的方法(參見圖11-2)。

5)代理之間是如何通信的呢?這要看以什么技術(shù)來實(shí)現(xiàn)它們。通常有三種選擇(options): (干貨——代理間的通信技術(shù))

  • o1) CORBA,通用對(duì)象請(qǐng)求代理架構(gòu): 支持任何編程語言編寫的對(duì)象之間的方法調(diào)用。CORBA使用Internet Inter-ORB協(xié)議(IIOP)支持對(duì)象間的通信。
  • o2) Web服務(wù)架構(gòu)是一個(gè)協(xié)議集,有時(shí)統(tǒng)一描述為WS-*。它也獨(dú)立于編程語言的,不過它使用基于XML的通信格式。用于傳輸對(duì)象的格式則是簡(jiǎn)單對(duì)象訪問協(xié)議(SOAP)。
  • o3) RMI,Java的遠(yuǎn)程方法調(diào)用技術(shù): 支持Java的分布式對(duì)象之間的方法調(diào)用。 (干貨——引入RMI)

5.1)與RMI不同,CORBA與SOAP都是完全獨(dú)立于語言的??蛻舳伺c服務(wù)器程序可以由C、C++、Java或者其他語言編寫。
5.2) Sun 開發(fā)了一個(gè)更簡(jiǎn)單的機(jī)制, 稱為遠(yuǎn)程方法調(diào)用-RMI: 專門針對(duì)java 應(yīng)用之間的通信;


【3】遠(yuǎn)程方法調(diào)用(RMI)

1) 分布式計(jì)算的關(guān)鍵是遠(yuǎn)程方法調(diào)用。 在一臺(tái)機(jī)器(稱為客戶端)上的某些代碼希望調(diào)用在另一臺(tái)機(jī)器(遠(yuǎn)程對(duì)象)上的某個(gè)對(duì)象的一個(gè)方法。要實(shí)現(xiàn)這一點(diǎn),方法的參數(shù)必須以某種方式傳遞到另一臺(tái)機(jī)器上,而服務(wù)器必須得到通知,去定位遠(yuǎn)程對(duì)象并執(zhí)行要調(diào)用的方法,并且必須將返回值傳遞回去。(干貨——分布式計(jì)算的關(guān)鍵是遠(yuǎn)程方法調(diào)用)


【3.1】存根與參數(shù)編組

1)存根: 當(dāng)客戶代碼要在遠(yuǎn)程對(duì)象上調(diào)用一個(gè)遠(yuǎn)程方法時(shí),實(shí)際上調(diào)用的是代理對(duì)象上的一個(gè)普通的方法,我們稱此代理對(duì)象為存根(stub)。 (干貨—— 存根是client 上的 agent object)

  • 1.1)看個(gè)荔枝:
    Warehouse centralWarehouse = get stub object;
    double price = centralWarehouse.getPrice(“Blackwell Toaster”);
  • 1.2)存根位于客戶端機(jī)器上,而非服務(wù)器上。它知道如何通過網(wǎng)絡(luò)與服務(wù)器聯(lián)系。
  • 1.3)存根將遠(yuǎn)程方法所需的參數(shù)打包成一組字節(jié)。
  • 1.4)參數(shù)編組:對(duì)參數(shù)編碼的過程稱作參數(shù)編組(parameter marshalling),參數(shù)編組的目的是將參數(shù)轉(zhuǎn)換成適合在虛擬機(jī)之間進(jìn)行傳遞的格式。在RMI協(xié)議中,對(duì)象是使用序列化機(jī)制進(jìn)行編碼的,第1章描述了這種機(jī)制。在SOAP協(xié)議中,對(duì)象被編碼為XML。 (干貨——參數(shù)編組定義)

2)總的來說,客戶端的存根方法構(gòu)造了一個(gè)信息塊,它由以下幾部分組成(parts):

  • p1)被使用的遠(yuǎn)程對(duì)象的標(biāo)識(shí)符;
  • p2)被調(diào)用的方法的描述;
  • p3)編組后的參數(shù);

3)然后,存根將此信息發(fā)送給服務(wù)器。在服務(wù)器一端,接收對(duì)象執(zhí)行以下動(dòng)作(actions):

  • a1)定位要調(diào)用的遠(yuǎn)程對(duì)象;
  • a2)調(diào)用所需的方法,并傳遞客戶端提供的參數(shù);
  • a3)捕獲返回值或該調(diào)用產(chǎn)生的異常;
  • a4)將返回值編組,打包送回給客戶端存根。

4) 反編組:客戶端存根對(duì)來自服務(wù)器端的返回值或異常進(jìn)行反編組,就成為了調(diào)用存根的返回值。如果遠(yuǎn)程方法拋出了一個(gè)異常,那么存根就在客戶端發(fā)起調(diào)用的處理空間中重新拋出該異常。圖11-3展示了一次遠(yuǎn)程方法調(diào)用的信息流。

Attention) 這個(gè)過程顯然很復(fù)雜,不過好消息是,這一切都是完全自動(dòng)的,而且在很大程度上,它對(duì)程序員是透明性。


【4】RMI 編程模型

【4.1 接口實(shí)現(xiàn)】

1) 如何實(shí)現(xiàn)和啟動(dòng)服務(wù)器與客戶端程序。 (干貨——如何實(shí)現(xiàn)和啟動(dòng)服務(wù)器與客戶端程序)

step1)遠(yuǎn)程對(duì)象的能力是由在客戶端和服務(wù)器之間共享的接口所表示的。例如,以下程序的接口描述了遠(yuǎn)程倉庫對(duì)象所提供的服務(wù):

public interface Warehouse extends Remote {double getPrice(String description) throws RemoteException; }

對(duì)以上代碼的分析(Analysis):

  • A1)遠(yuǎn)程對(duì)象的接口必須擴(kuò)展Remote接口,它位于java.rmi包中。
  • A2)接口中的所有方法還必須聲明拋出RemoteException異常,這是因?yàn)檫h(yuǎn)程方法調(diào)用與生俱來就缺乏本地調(diào)用的可靠性,遠(yuǎn)程調(diào)用總是存在失敗的可能。

step2) 接下來,在服務(wù)器端,必須提供這樣的類,它真正實(shí)現(xiàn)了在遠(yuǎn)程接口中聲明的工作。

public class WarehouseImpl extends UnicastRemoteObject implements Warehouse {public WarehouseImpl() throws RemoteException{prices = new HashMap<String, Double>();prices.put("Blackwell Toaster", 24.95);prices.put("ZapXpress Microwave Oven", 49.95);}public double getPrice(String description) throws RemoteException{Double price = prices.get(description);return price == null ? 0 : price;}private Map<String, Double> prices; }

Attention) UnicastRemoteObject類 :你可以看出這個(gè)類是遠(yuǎn)程方法調(diào)用的目標(biāo),因?yàn)樗^承自UnicastRemoteObject,這個(gè)類的構(gòu)造器使得它的對(duì)象可供遠(yuǎn)程訪問。
2)problem+solution:

  • 2.1)problem:有時(shí)候可能不希望服務(wù)器類繼承UnicastRemoteObject,也許是因?yàn)閷?shí)現(xiàn)類已經(jīng)繼承了其他的類。
  • 2.2)solution:在這種情況下,讀者需要親自初始化遠(yuǎn)程對(duì)象,并將它們傳給靜態(tài)的exportObject方法。如果不繼承UnicastRemoteObject,可以在遠(yuǎn)程對(duì)象的構(gòu)造器中像下面這樣調(diào)用exportObject方法。
    UnicastRemoteObject.exportObject(this, 0); // 第二個(gè)參數(shù)是0,表明任意合適的端口都可用來監(jiān)聽客戶端連接。

Attention) Unicast這個(gè)術(shù)語是指我們是通過產(chǎn)生對(duì)單一的IP地址和端口的調(diào)用來定位遠(yuǎn)程對(duì)象的這一事實(shí)。這是Java SE中唯一支持的機(jī)制。更復(fù)雜的分布式對(duì)象系統(tǒng)(諸如JINI)會(huì)考慮到對(duì)在多個(gè)不同的服務(wù)器上的遠(yuǎn)程對(duì)象的”Multicast”查找。 (干貨——這里提到了JINI)

intro to jini ( from http://baike.baidu.com/link?url=2uT-UgPQerl5Xze13Xqyg0e9eVTH5SOI6ucWnFw_nMKHw8754Lc1H_eM94gxiM7U0U9FUttdQd1yZCiBeYvVlK)
Jini(Java Intelligent Network Infrastructure)是Sun公司的研究與開發(fā)項(xiàng)目,它能極大擴(kuò)展Java技術(shù)的能力。Jini技術(shù)可使范圍廣泛的多種硬件和軟件—即可與網(wǎng)絡(luò)相連的任何實(shí)體—能夠自主聯(lián)網(wǎng)。
Jini可以使人們極其簡(jiǎn)單地使用網(wǎng)絡(luò)設(shè)備和網(wǎng)絡(luò)服務(wù),就象今天我們使用電話一樣—通過網(wǎng)絡(luò)撥號(hào)即插即用。Jini的目標(biāo)是最大限度地簡(jiǎn)化與網(wǎng)絡(luò)的交互性。


【4.2】RMI注冊(cè)表

1)problem+solution:

  • 1.1)problem:要訪問服務(wù)器上的一個(gè)遠(yuǎn)程對(duì)象時(shí),客戶端首先需要一個(gè)本地的存根對(duì)象??墒强蛻舳巳绾螌?duì)該存根發(fā)出請(qǐng)求呢?最普通的方法是調(diào)用另一個(gè)服務(wù)對(duì)象上的一個(gè)遠(yuǎn)程方法,以返回值的方式取得存根對(duì)象。然而,這就成了先有雞還是先有蛋的問題。
  • 1.2)solution:第一個(gè)遠(yuǎn)程對(duì)象總要通過某種方式進(jìn)行定位。為此,JDK提供了自舉注冊(cè)服務(wù)(bootstrap registry service)。

2)如何注冊(cè)一個(gè)遠(yuǎn)程對(duì)象? (干貨——如何注冊(cè)一個(gè)遠(yuǎn)程對(duì)象)
服務(wù)器程序使用自舉注冊(cè)服務(wù)來注冊(cè)至少一個(gè)遠(yuǎn)程對(duì)象。要注冊(cè)一個(gè)遠(yuǎn)程對(duì)象,需要一個(gè)RMI URL和一個(gè)對(duì)實(shí)現(xiàn)對(duì)象的引用。RMI的URL以rmi:開頭,后接服務(wù)器以及一個(gè)可選的端口號(hào),接著是遠(yuǎn)程對(duì)象的名字。例如: rmi://localhost:99/central_warehouse
3)默認(rèn)情況下,主機(jī)名是localhost,端口為1099。 服務(wù)器告訴注冊(cè)表在給定位置將該對(duì)象關(guān)聯(lián)或”綁定”到這個(gè)名字。

  • 3.1)下面的代碼將一個(gè)WarehouseImpl對(duì)象注冊(cè)到了同一個(gè)服務(wù)器上的RMI注冊(cè)表中: (干貨——綁定遠(yuǎn)程對(duì)象到server上的RMI注冊(cè)表中)
    WarehouseImpl centralWarehouse = new WarehouseImpl();
    Context namingContext = new InitialContext();
    namingContext.bind(“rmi:central_warehouse”, centralWarehouse);

  • 3.2) 看個(gè)荔枝:下面的程序只是構(gòu)造并注冊(cè)了一個(gè)WarehouseImpl對(duì)象

Attention) 基于安全原因,一個(gè)應(yīng)用只有當(dāng)它與注冊(cè)表運(yùn)行在同一個(gè)服務(wù)器時(shí),該應(yīng)用才可以綁定、取消綁定,或重綁定注冊(cè)對(duì)象的引用。
4)客戶端可以通過下面的調(diào)用枚舉所有注冊(cè)過的RMI對(duì)象: (干貨——注意是client 端枚舉 出 server 端 注冊(cè)過的RMI對(duì)象)

Enumeration<NameClassPair> e = namingContext.list("rmi://regserver.mycompany.com")

5)NameClassPair是一個(gè)助手類: 它包含綁定對(duì)象的名字和該對(duì)象所屬類的名字。

  • 5.1)看個(gè)荔枝: 例如,下面的代碼可以顯示所有注冊(cè)對(duì)象的名字:
    while (e.hasMoreElements())
    System.out.println(e.nextElement().getName());

6)客戶端可以通過下面的方式,來指定服務(wù)器和遠(yuǎn)程對(duì)象的名字,以此獲得訪問遠(yuǎn)程對(duì)象所需的存根: (干貨——client端獲得存根)

String url = "rmi://regserver.mycompany.com/central_warehouse"; Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url);

Attention) 在一個(gè)全局注冊(cè)表中,想保持一個(gè)名字的惟一性非常困難,因此不應(yīng)該將此技術(shù)作為定位服務(wù)器端對(duì)象的一般方法。相反,自舉服務(wù)只應(yīng)該用來注冊(cè)非常少的遠(yuǎn)程對(duì)象。然后使用這些對(duì)象來定位其他的對(duì)象。 (干貨——自舉服務(wù)的局限性)
7) 代碼11-4展示了客戶端如何獲得遠(yuǎn)程倉庫對(duì)象的存根,并調(diào)用遠(yuǎn)程的getPrice方法。


【4.3】部署程序(you can also refer to http://www.cnblogs.com/leslies2/archive/2011/05/20/2051844.html)

0)部署前的準(zhǔn)備

  • 0.1)創(chuàng)建兩個(gè)目錄, 分別存放用于啟動(dòng)server 和 client 的類:

    server/
    WarehouseServer.class
    Warehouse.class
    WarehouseImpl.class
    client/
    WarehouseClient.class
    Warehouse.class

  • 0.2)當(dāng)部署RMI 應(yīng)用時(shí), 通常需要?jiǎng)討B(tài)地將類交付給運(yùn)行程序,其中一個(gè)例子就是RMI注冊(cè)表。請(qǐng)記住注冊(cè)表的一個(gè)實(shí)例要服務(wù)許多不同的RMI應(yīng)用。RMI注冊(cè)表需要有權(quán)限訪問注冊(cè)的服務(wù)接口的類文件,但是,當(dāng)注冊(cè)表啟動(dòng)時(shí),無法預(yù)測(cè)將來會(huì)產(chǎn)生的所有注冊(cè)請(qǐng)求。因此,RMI 注冊(cè)表會(huì)動(dòng)態(tài)地加載之前從未遇到過的所有遠(yuǎn)程接口的類文件;

  • 0.3)動(dòng)態(tài)交付的類文件是通過標(biāo)準(zhǔn)的web server發(fā)布的。在我們所舉的case中, server程序 需要使用 Warehouse.class 文件 對(duì)于 RMI 注冊(cè)表來說是可以獲得的,因此將這個(gè)文件放到了第三個(gè)稱為download 目錄中的:

    download/
    Warehouse.class

  • 0.4)下面,我們用 web server 來訪問這個(gè)目錄中的內(nèi)容(NanoHTTPD web server)

1)當(dāng)應(yīng)用被部署時(shí),服務(wù)器、RMI注冊(cè)表、Web服務(wù)器和客戶端可以定位到四臺(tái)不同的計(jì)算機(jī)上,參見圖11-5。但是,出于測(cè)試的目的,我們將只使用一臺(tái)計(jì)算機(jī)。

Attention) 由于安全的原因,作為JDK一部分的rmiregistry服務(wù)只允許來自同一臺(tái)主機(jī)的綁定調(diào)用。也就是說,服務(wù)器和rmiregistry進(jìn)程需要定位在同一臺(tái)計(jì)算機(jī)上。但是,RMI架構(gòu)允許更通用的支持多臺(tái)服務(wù)器的RMI注冊(cè)表實(shí)現(xiàn)。 (干貨——基于安全原因,服務(wù)器和rmiregistry進(jìn)程需要定位在同一臺(tái)計(jì)算機(jī)上)
2)測(cè)試遠(yuǎn)程方法調(diào)用:

  • step1)打開一個(gè)新的控制臺(tái)窗口,轉(zhuǎn)到download目錄,然后將NanoHTTPD.java(NanoHTTPD web 服務(wù)器)復(fù)制到這個(gè)目錄中。使用下面的命令來編譯該源文件并啟動(dòng)這個(gè)web服務(wù)器: java NanoHTTPD 8080

  • step2)打開另一個(gè)控制臺(tái)窗口,轉(zhuǎn)到不包含任何類文件的某個(gè)目錄,并啟動(dòng)RMI注冊(cè)表:rmiregistry

Attention)

  • A1)在啟動(dòng)RMI注冊(cè)表之前,請(qǐng)確保CLASSPATH環(huán)境變量沒有進(jìn)行任何設(shè)置,并仔細(xì)檢查當(dāng)前目錄是否確實(shí)不包含任何類文件。否則,RMI注冊(cè)表可能會(huì)找到一些假冒的類文件,這使得注冊(cè)表需要從另一個(gè)不同的來源下載額外的類文件時(shí),產(chǎn)生混淆。
  • A2)簡(jiǎn)單地講,每個(gè)存根對(duì)象都有一個(gè)代碼基項(xiàng),指出了它是從何處加載的。這個(gè)代碼基被用來加載它所依賴的類。如果RMI注冊(cè)表在本地找到了這樣的類,那么它的代碼基就會(huì)被設(shè)置為錯(cuò)誤的值。
  • A3)推薦在server 程序中通過代碼注冊(cè)通訊端口和注冊(cè)通訊路徑 (干貨——不推薦使用 rmiregistry命令行)

    // 注冊(cè)通訊端口
    LocateRegistry.createRegistry(1099);
    // 注冊(cè)通訊路徑
    Naming.rebind(“rmi://localhost:1099/warehouseService”, warehouseService);

  • step3)現(xiàn)在已經(jīng)準(zhǔn)備好啟動(dòng)服務(wù)器了。打開第三個(gè)控制臺(tái)窗口,轉(zhuǎn)到server目錄,并執(zhí)行下面的命令:

    java -Djava.rmi.server.codebase=http://localhost:8080/ WarehouseServer // java.rmi.server.codebase屬性指出了服務(wù)類文件的URL。服務(wù)器程序?qū)⑦@個(gè)URL傳遞給RMI注冊(cè)表。

  • Warning) 確保代碼基URL以斜杠”/”結(jié)尾非常重要。
  • step4)最后,打開第四個(gè)控制臺(tái)窗口,轉(zhuǎn)到client目錄,運(yùn)行:

  • 你將會(huì)看到一條短消息,表示運(yùn)行方法被成功調(diào)用, 參見圖11-6所示;


【4.4】記錄 RMI 活動(dòng)的日志

1) 如果用下面的選項(xiàng)啟動(dòng)服務(wù)器:

-Djava.rmi.server.logCalls=true WarehouseServer & // 那么服務(wù)器會(huì)在其控制臺(tái)上記錄所有的遠(yuǎn)程方法調(diào)用到日志中。
java -Djava.rmi.server.logCalls=true -Djava.rmi.server.codebase=http://localhost:8080/ com.corejava.chapter11.server.WarehouseServer

2) 如果想查看額外的日志信息,就必須用標(biāo)準(zhǔn)的Java日志API配置日志記錄器。

  • 2.1) 可以用下面的內(nèi)容創(chuàng)建一個(gè)logging.properties文件。

    handlers=java.util.logging.ConsoleHandler
    sun.rmi.loader.level=FINE
    java.util.logging.ConsoleHandler.level=FINE
    java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

  • 2.2)我們可以對(duì)設(shè)置進(jìn)行調(diào)整,方法是為每一個(gè)記錄器設(shè)置單獨(dú)的等級(jí)而不是設(shè)置全局等級(jí)。例如,要跟蹤類的加載行為,可以設(shè)置為:

    sun.rmi.loader.level=FINE

  • 2.3)用以下選項(xiàng)啟動(dòng)RMI注冊(cè)表

    -Djava.util.logging.config.file=directory/logging.properties

  • 2.4)用以下選項(xiàng)啟動(dòng)客戶端與服務(wù)器

    -Djava.util.logging.config.file=directory/logging.properties

  • 2.5)表11-1 列出了所有的RMI 日志記錄器:

總結(jié)

以上是生活随笔為你收集整理的java分布式对象(RMI+部署使用RMI的程序)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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