首頁  >  文章  >  Java  >  Java RMI圖文詳解(附範例)

Java RMI圖文詳解(附範例)

尚
轉載
2019-12-24 17:33:295917瀏覽

Java RMI圖文詳解(附範例)

Java RMI:Java遠端方法調用,即Java RMI(Java Remote Method Invocation)是Java程式語言裡,一種用於實現遠端過程調用的應用程式介面。

它使客戶機上運行的程式可以呼叫遠端伺服器上的物件。遠端方法呼叫特性使Java程式設計人員能夠在網路環境中分佈操作。 RMI全部的宗旨就是盡可能簡化遠端介面物件的使用。

我們知道遠端過程呼叫(Remote Procedure Call, RPC)可以用於一個進程呼叫另一個進程(很可能在另一個遠端主機上)中的過程,從而提供了過程的分佈能力。 Java 的 RMI 則在 RPC 的基礎上向前又邁進了一步,即提供分散式物件間的通訊。

RMI(Remote Method Invocation)為遠端方法調用,是允許運行在一個Java虛擬機的物件調用運行在另一個Java虛擬機器上的物件的方法。

這兩台虛擬機器可以是運作在相同電腦上的不同流程中,也可以是運作在網路上的不同電腦中。

【JavaRMI】

一、工作原理

RMI能讓一個Java程式去呼叫網路中另一台電腦的Java物件的方法,那麼呼叫的效果就像是在本機上呼叫一樣。通俗的講:A機器上面有一個class,透過遠端調用,B機器調用這個class 中的方法。

RMI,遠端方法呼叫(Remote Method Invocation)是Enterprise JavaBeans的支柱,是建立分散式Java應用程式的方便途徑。 RMI是非常容易使用的,但它非常的強大。

RMI的基礎是接口,RMI架構基於一個重要的原理:定義接口和定義接口的具體實現是分開的。下面我們透過具體的例子,建立一個簡單的遠端運算服務和使用它的客戶程式

二、RMI包含部分:

1、遠端服務的接口定義

2、遠端服務介面的具體實作

3、樁(Stub)和框架(Skeleton)檔案

4、一個運行遠端服務的伺服器

5、一個RMI命名服務,它允許客戶端去發現這個遠端服務

6、類別檔案的提供者(一個HTTP或FTP伺服器)

7、一個需要這個遠端服務的客戶端程式

三、RMI的用途?

#RMI的用途是為分散式Java應用程式之間的遠端通訊提供服務,提供分佈式服務。

目前主要應用時封裝在各個J2EE專案框架中,例如Spring,EJB(Spring和EJB均封裝了RMI技術)

在Spring中實作RMI:

①在伺服器端定義服務的接口,定義特定的類別實作這些接口;

②在伺服器端使用org.springframework.remoting.rmi.RmiServiceExporter類別來註冊服務;

③在客戶端使用org.springframework.remoting.rmi.RmiProxyFactoryBean來實作遠端服務的代理功能;

④在客戶端定義存取與伺服器端服務介面相同的類別

# 、RMI的局限?                                         

RMI目前使用Java遠端訊息交換協定JRMP(Java Remote Messaging Protocol)進行通訊。 JRMP是專為Java的遠端物件製定的協議,由於JRMP是專為Java物件製定的,因此,RMI對於使用非Java語言開發的應用系統的支援不足。

不能與用非Java語言書寫的物件通訊(意思是只支援客戶端和伺服器端都是Java程式的程式碼的遠端呼叫)。

五、RMI的使用限制?

由於客戶機和伺服器都是使用Java編寫的,二者平台相容性的要求只是雙方都運作在版本相容的Java虛擬機器上。

六、RMI呼叫遠端方法的參數和傳回值

當呼叫遠端物件上的方法時,客戶機除了可以將原始類型的資料作為參數一外,還可以將對像作為參數來傳遞,與之相對應的是返回值,可以返回原始類型或對象,這些都是透過Java的對象序列化(serialization)技術來實現的。 (換而言之:參數或傳回值如果是物件的話必須實作Serializable介面)

#七、 RMI應用程式的基本模型

Java RMI圖文詳解(附範例)

Java RMI圖文詳解(附範例)

######################### #######八、RMI體系結構###################樁/框架(Stub/Skeleton)層:客戶端的樁和伺服器端的框架;## #

遠端引用(remote reference)層:處理遠端引用行為

傳送層(transport):連線的建立與管理,以及遠端物件的追蹤

九、 RMI類別和介面(完成一個簡單RMI需要用到的類別)。

Java RMI圖文詳解(附範例)

(一) Remote介面:是一個不定義方法的標記介面

Public interface Remote{}

#在RMI中,遠端介面宣告了可以從遠端Java虛擬機器呼叫的方法集。遠端介面符合下列要求:

1、遠端介面必須直接或間接擴充Java.rmi.Remote接口,且必須宣告為public,除非客戶端於遠端介面在同一包中

2.在遠端介面中的方法在宣告時,除了要拋出與應用程式有關的一場之外,還必須包括RemoteException(或它的超類,IOExcepion或Exception)異常

#3、在遠端方法聲明中,作為參數或傳回值聲明的遠端物件必須聲明為遠端接口,而非該介面的實作類別。

(二) RemoteObject抽象類別實作了Remote介面和序列化Serializable接口,它和它的子類別提供RMI伺服器函數。

(三) LocateRegistry final()類別用於取得特定主機的引導遠端物件註冊伺服器程式的參考(即建立stub),或建立能在特定連接埠接收呼叫的遠端物件註冊服務程式。

伺服器端:向其他客戶機提供遠端物件服務

SomeService servcie=……;//远程对象服务

1、Registry registry=LocateRegisty.getRegistry();//Registry是個接口,他繼承了Remote,此方法傳回本地主機在預設註冊表連接埠1099 上對遠端物件Registry 的參考。

2、getRegistry(int port) 傳回本機在指定port 上對遠端物件Registry 的參考;

3、getRegistry(String host)  傳回指定host 在預設登錄機埠1099 上遠端物件Registry 的參考;

4、getRegistry(String host, int port) 傳回指定的host 和port 上對遠端物件Registry 的參考

#5、registry.bind(「I serve”,service);// bind(String name,Remote obj) 綁定對此註冊表中指定name 的遠端參考。 name : 與此遠端參考相關的名稱 obj : 移除遠端物件(通常是一個 stub)的參考

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

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

#8、 lookup(String name) 傳回註冊表中綁定到指定name 的遠端引用,傳回Remote

9、String[] list()   傳回在此登錄中所綁定的名稱的陣列。該陣列將包含一個此註冊表中呼叫此方法時綁定的名稱快照。

客戶機端:向伺服器提供對應的服務請求。

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

Java RMI圖文詳解(附範例)

##(四) Naming類別和Registry類別類似。

客戶端:

Naming.lookup(String url)
url 格式如下"rmi://localhost/"+远程对象引用

伺服器端:

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

(五) RMISecurityManager類別

在RMI引用程式中,如果沒有設定安全管理器,則只能從本機類別路徑載入stub和類,這可以確保應用程式不受遠端方法呼叫所下載的程式碼侵害

在從遠端主機下載程式碼之前必須執行下列程式碼來安裝RMISecurityManager:

System.setSecurityManager(new RMISecurityManager());

#第十、demo開發

###為了寫一個demo,我們分成兩個部分,一部分是server端的程式碼,一部分是client端的程式碼,client端的程式碼主要是為了使用server端的程式碼。當然這個程式碼是非常簡單的,只是為了說明問題,現實的使用會讓比較複雜的。 ######(一) 我們的目的######建立一個server端的java project,包含遠端的程式碼,定義接口,定義接口實現,然後在建立一個client端的java project,透過RMI使用遠端服務中的方法。 ######(二) 我們的程式碼結構###############(三) 遠端服務代碼######1. 遠端服務的介面定義### ###第一步就是建立和編譯服務介面的Java程式碼。這個介面定義了所有的提供遠端服務的功能,以下是原始程式:######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. 介面的具體實作######第二步就是對於上面的介面進行實作:######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 ,實作implements Serializable序列化介面。也就是可以在client和server端進行傳輸的可序列化物件。 ######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 导出Export成jar包,命名为:RmiServerInterface.jar。导入到client中。

2、项目——右键——Export——java——jar file——next——选择Account类和接口UserManagerInterface——命名为:RmiServerInterface.jar如下图:

Java RMI圖文詳解(附範例)

3. 新建一个java Project,导入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. 先运行服务器端代码, 然后运行客户端代码,就会显示运行结果,客户端可以运行多次,每次都可以取得服务器端的对象。如果要再次运行客户端代码就需要更改端口号,如果不更改就会显示端口号被占用。

更多java知识请关注java基础教程栏目。

以上是Java RMI圖文詳解(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除