溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java RMI是什么

發(fā)布時間:2020-06-15 11:41:22 來源:億速云 閱讀:493 作者:Leah 欄目:編程語言

Java RMI是什么?相信大部分人都不太了解,今天小編為了讓大家更加了解Java RMI,給大家總結(jié)了以下內(nèi)容,跟隨小編一起來看看吧。                                                          

Java RMI:Java遠(yuǎn)程方法調(diào)用,即Java RMI(Java Remote Method Invocation)是Java編程語言里,一種用于實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用的應(yīng)用程序編程接口。

它使客戶機(jī)上運(yùn)行的程序可以調(diào)用遠(yuǎn)程服務(wù)器上的對象。遠(yuǎn)程方法調(diào)用特性使Java編程人員能夠在網(wǎng)絡(luò)環(huán)境中分布操作。RMI全部的宗旨就是盡可能簡化遠(yuǎn)程接口對象的使用。

我們知道遠(yuǎn)程過程調(diào)用(Remote Procedure Call, RPC)可以用于一個進(jìn)程調(diào)用另一個進(jìn)程(很可能在另一個遠(yuǎn)程主機(jī)上)中的過程,從而提供了過程的分布能力。Java 的 RMI 則在 RPC 的基礎(chǔ)上向前又邁進(jìn)了一步,即提供分布式對象間的通訊。

RMI(Remote Method Invocation)為遠(yuǎn)程方法調(diào)用,是允許運(yùn)行在一個Java虛擬機(jī)的對象調(diào)用運(yùn)行在另一個Java虛擬機(jī)上的對象的方法。

這兩個虛擬機(jī)可以是運(yùn)行在相同計(jì)算機(jī)上的不同進(jìn)程中,也可以是運(yùn)行在網(wǎng)絡(luò)上的不同計(jì)算機(jī)中。

【JavaRMI】

一、工作原理

RMI能讓一個Java程序去調(diào)用網(wǎng)絡(luò)中另一臺計(jì)算機(jī)的Java對象的方法,那么調(diào)用的效果就像是在本機(jī)上調(diào)用一樣。通俗的講:A機(jī)器上面有一個class,通過遠(yuǎn)程調(diào)用,B機(jī)器調(diào)用這個class 中的方法。

RMI,遠(yuǎn)程方法調(diào)用(Remote Method Invocation)是Enterprise JavaBeans的支柱,是建立分布式Java應(yīng)用程序的方便途徑。RMI是非常容易使用的,但是它非常的強(qiáng)大。

RMI的基礎(chǔ)是接口,RMI構(gòu)架基于一個重要的原理:定義接口和定義接口的具體實(shí)現(xiàn)是分開的。下面我們通過具體的例子,建立一個簡單的遠(yuǎn)程計(jì)算服務(wù)和使用它的客戶程序

二、RMI包含部分:

1、遠(yuǎn)程服務(wù)的接口定義

2、遠(yuǎn)程服務(wù)接口的具體實(shí)現(xiàn)

3、樁(Stub)和框架(Skeleton)文件

4、一個運(yùn)行遠(yuǎn)程服務(wù)的服務(wù)器

5、一個RMI命名服務(wù),它允許客戶端去發(fā)現(xiàn)這個遠(yuǎn)程服務(wù)

6、類文件的提供者(一個HTTP或者FTP服務(wù)器)

7、一個需要這個遠(yuǎn)程服務(wù)的客戶端程序

三、RMI的用途?

RMI的用途是為分布式Java應(yīng)用程序之間的遠(yuǎn)程通信提供服務(wù),提供分布式服務(wù)。

目前主要應(yīng)用時封裝在各個J2EE項(xiàng)目框架中,例如Spring,EJB(Spring和EJB均封裝了RMI技術(shù))

在Spring中實(shí)現(xiàn)RMI:

①在服務(wù)器端定義服務(wù)的接口,定義特定的類實(shí)現(xiàn)這些接口;

②在服務(wù)器端使用org.springframework.remoting.rmi.RmiServiceExporter類來注冊服務(wù);

③在客戶端使用org.springframework.remoting.rmi.RmiProxyFactoryBean來實(shí)現(xiàn)遠(yuǎn)程服務(wù)的代理功能;

④在客戶端定義訪問與服務(wù)器端服務(wù)接口相同的類

四、RMI的局限?                                                                    

RMI目前使用Java遠(yuǎn)程消息交換協(xié)議JRMP(Java Remote Messaging Protocol)進(jìn)行通信。JRMP是專為Java的遠(yuǎn)程對象制定的協(xié)議,由于JRMP是專為Java對象制定的,因此,RMI對于用非Java語言開發(fā)的應(yīng)用系統(tǒng)的支持不足。

不能與用非Java語言書寫的對象進(jìn)行通信(意思是只支持客戶端和服務(wù)器端都是Java程序的代碼的遠(yuǎn)程調(diào)用)。

五、RMI的使用局限?

由于客戶機(jī)和服務(wù)器都是使用Java編寫的,二者平臺兼容性的要求僅僅是雙方都運(yùn)行在版本兼容的Java虛擬機(jī)上。

六、RMI調(diào)用遠(yuǎn)程方法的參數(shù)和返回值

當(dāng)調(diào)用遠(yuǎn)程對象上的方法時,客戶機(jī)除了可以將原始類型的數(shù)據(jù)作為參數(shù)一外,還可以將對象作為參數(shù)來傳遞,與之相對應(yīng)的是返回值,可以返回原始類型或?qū)ο?,這些都是通過Java的對象序列化(serialization)技術(shù)來實(shí)現(xiàn)的。(換而言之:參數(shù)或者返回值如果是對象的話必須實(shí)現(xiàn)Serializable接口)

七、 RMI應(yīng)用程序的基本模型

Java RMI是什么

八、RMI體系結(jié)構(gòu)

Java RMI是什么

樁/框架(Stub/Skeleton)層:客戶端的樁和服務(wù)器端的框架;

遠(yuǎn)程引用(remote reference)層:處理遠(yuǎn)程引用行為

傳送層(transport):連接的建立和管理,以及遠(yuǎn)程對象的跟蹤

九、 RMI類和接口(完成一個簡單RMI需要用到的類)。

Java RMI是什么

(一) Remote接口:是一個不定義方法的標(biāo)記接口

Public interface Remote{}

在RMI中,遠(yuǎn)程接口聲明了可以從遠(yuǎn)程Java虛擬機(jī)中調(diào)用的方法集。遠(yuǎn)程接口滿足下列要求:

1、遠(yuǎn)程接口必須直接或間接擴(kuò)展Java.rmi.Remote接口,且必須聲明為public,除非客戶端于遠(yuǎn)程接口在同一包中

2、在遠(yuǎn)程接口中的方法在聲明時,除了要拋出與應(yīng)用程序有關(guān)的一場之外,還必須包括RemoteException(或它的超類,IOExcepion或Exception)異常

3、在遠(yuǎn)程方法聲明中,作為參數(shù)或返回值聲明的遠(yuǎn)程對象必須聲明為遠(yuǎn)程接口,而非該接口的實(shí)現(xiàn)類。

(二) RemoteObject抽象類實(shí)現(xiàn)了Remote接口和序列化Serializable接口,它和它的子類提供RMI服務(wù)器函數(shù)。

(三) LocateRegistry final()類用于獲得特定主機(jī)的引導(dǎo)遠(yuǎn)程對象注冊服務(wù)器程序的引用(即創(chuàng)建stub),或者創(chuàng)建能在特定端口接收調(diào)用的遠(yuǎn)程對象注冊服務(wù)程序。

服務(wù)器端:向其他客戶機(jī)提供遠(yuǎn)程對象服務(wù)

SomeService servcie=……;//遠(yuǎn)程對象服務(wù)

1、Registry registry=LocateRegisty.getRegistry();//Registry是個接口,他繼承了Remote,此方法返回本地主機(jī)在默認(rèn)注冊表端口 1099 上對遠(yuǎn)程對象 Registry 的引用。

2、getRegistry(int port) 返回本地主機(jī)在指定 port 上對遠(yuǎn)程對象 Registry 的引用;

3、getRegistry(String host)  返回指定 host 在默認(rèn)注冊表端口 1099 上對遠(yuǎn)程對象 Registry 的引用;

4、getRegistry(String host, int port) 返回指定的 host 和 port 上對遠(yuǎn)程對象 Registry 的引用

5、registry.bind(“I serve”,service);// bind(String name,Remote obj) 綁定對此注冊表中指定 name 的遠(yuǎn)程引用。name : 與該遠(yuǎn)程引用相關(guān)的名稱 obj : 對遠(yuǎn)程對象(通常是一個 stub)的引用

6、unbind(String name)移除注冊表中指定name的綁定。

7、rebind(String name,Remote obj)重新綁定,如果name已存在,但是Remote不一樣則替換,如果Remote一樣則丟棄現(xiàn)有的綁定

8、lookup(String name) 返回注冊表中綁定到指定 name 的遠(yuǎn)程引用,返回Remote

9、String[] list()   返回在此注冊表中綁定的名稱的數(shù)組。該數(shù)組將包含一個此注冊表中調(diào)用此方法時綁定的名稱快照。

客戶機(jī)端:向服務(wù)器提供相應(yīng)的服務(wù)請求。

Registry registry=LocateRegisty.getRegistry();
SomeService servcie=(SomeService)registry.lookup(“I serve”);
Servcie.requestService();

(四) Naming類和Registry類類似。

客戶端:

Naming.lookup(String url)
url 格式如下"rmi://localhost/"+遠(yuǎn)程對象引用

服務(wù)器端:

Registry registry=LocateRegistry.createRegistry(int port);
Naming.rebind(“service”,service);

(五) RMISecurityManager類

在RMI引用程序中,如果沒有設(shè)置安全管理器,則只能從本地類路徑加載stub和類,這可以確保應(yīng)用程序不受由遠(yuǎn)程方法調(diào)用所下載的代碼侵害

在從遠(yuǎn)程主機(jī)下載代碼之前必須執(zhí)行以下代碼來安裝RMISecurityManager:

System.setSecurityManager(new RMISecurityManager());

十、demo開發(fā)

為了編寫一個demo,我們分為兩部分,一部分是server端的代碼,一部分是client端的代碼,client端的代碼主要是為了使用server端的代碼。當(dāng)然這個代碼是非常簡單的,只是為了說明問題,現(xiàn)實(shí)的使用會使比較復(fù)雜的。

(一) 我們的目的

建立一個server端的java project,包含遠(yuǎn)程端的代碼,定義接口,定義接口實(shí)現(xiàn),然后在建立一個client端的java project,通過RMI使用遠(yuǎn)端服務(wù)中的方法。

(二) 我們的代碼結(jié)構(gòu)

Java RMI是什么

(三) 遠(yuǎn)程服務(wù)代碼

1. 遠(yuǎn)程服務(wù)的接口定義

第一步就是建立和編譯服務(wù)接口的Java代碼。這個接口定義了所有的提供遠(yuǎn)程服務(wù)的功能,下面是源程序:

UserManagerInterface.java

package cn.com.tt.rmiserver.stub;

import java.rmi.Remote;
import java.rmi.RemoteException;

import cn.com.tt.rmiserver.bean.Account;

public interface UserManagerInterface extends Remote{
    public String getUserName() throws RemoteException;
    public Account getAdminAccount() throws RemoteException;
}

接口必須繼承Remote類,每一個定義地方法都要拋出RemoteException異常對象。

2. 接口的具體實(shí)現(xiàn)

第二步就是對于上面的接口進(jìn)行實(shí)現(xiàn):

UserManagerImp.java

package cn.com.tt.rmiserver;

import java.rmi.RemoteException;

import cn.com.tt.rmiserver.stub.UserManagerInterface;
import cn.com.tt.rmiserver.bean.Account;

public class UserManagerImp implements UserManagerInterface {
    public UserManagerImp() throws RemoteException {

    }
    private static final long serialVersionUID = -3111492742628447261L;

    public String getUserName() throws RemoteException{
        return "TT";
    }
    public Account getAdminAccount() throws RemoteException{
        Account account=new Account();
        account.setUsername("TT");
        account.setPassword("123456");
        return account;
    }
}

3. 定義一個bean,實(shí)現(xiàn)implements Serializable序列化接口。也就是可以在client和server端進(jìn)行傳輸?shù)目尚蛄谢瘜ο蟆?/p>

Account.java

package cn.com.tt.rmiserver.bean;

import java.io.Serializable;

public class Account implements Serializable,Cloneable{
    private static final long serialVersionUID = -1858518369668584532L;
    private String username;
    private String password;
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

4. 定義server端的主程序入口。

Entry.java

package cn.com.tt.rmiserver.entry;

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import cn.com.tt.rmiserver.UserManagerImp;
import cn.com.tt.rmiserver.stub.UserManagerInterface;

public class Entry {
    public static void main(String []args) throws AlreadyBoundException, RemoteException{
        UserManagerImp userManager=new UserManagerImp();
        UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0);
        // Bind the remote object's stub in the registry
        Registry registry = LocateRegistry.createRegistry(2002);
       
        registry.rebind("userManager", userManagerI);
        System.out.println("server is ready");
        }
}

(四) client端代碼

1、把Server端的Account類和接口UserManagerInterface 導(dǎo)出Export成jar包,命名為:RmiServerInterface.jar。導(dǎo)入到client中。

2、項(xiàng)目——右鍵——Export——java——jar file——next——選擇Account類和接口UserManagerInterface——命名為:RmiServerInterface.jar如下圖:

Java RMI是什么

3. 新建一個java Project,導(dǎo)入jar包,編寫客戶端代碼。

4. 代碼

ClientEntry.java

package weiblog.rmi;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import cn.com.tt.rmiserver.stub.UserManagerInterface;

public class ClientEntry {
    
    public static void main(String []args){
        
        try {
            Registry registry = LocateRegistry.getRegistry("localhost",2004);
            UserManagerInterface userManager = (UserManagerInterface)registry.lookup("userManager");
            System.out.println("用戶名是"+userManager.getAdminAccount().getUsername()
                    +"密碼"+userManager.getAdminAccount().getPassword());
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NotBoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

}

5. 先運(yùn)行服務(wù)器端代碼, 然后運(yùn)行客戶端代碼,就會顯示運(yùn)行結(jié)果,客戶端可以運(yùn)行多次,每次都可以取得服務(wù)器端的對象。如果要再次運(yùn)行客戶端代碼就需要更改端口號,如果不更改就會顯示端口號被占用。

看完上述內(nèi)容,你們對Java RMI是什么有進(jìn)一步的了解嗎?如果還想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI