John Squirrels
等級 41
San Francisco

Java RMI

在 Toto sisi 群組發布
你好!今天我們將考慮一個相當有趣的話題:Java RMI。這代表遠程方法調用。您可以使用 RMI 允許兩個程序相互通信,即使它們位於不同的計算機上。這聽起來很酷嗎?:) 而且做起來並不難!在今天的課程中,我們將分析 RMI 交互的元素並弄清楚如何配置它。我們首先需要的是客戶端和服務器。我們真的不需要深入研究計算機術語。對於 RMI,這只是兩個程序。其中一個將包含一個對象,另一個將調用該對象的方法。調用存在於不同程序中的對象的方法——這是我們尚未完成的事情!是時候嘗試一下了!:) 為了避免陷入困境,讓' 讓我們的程序保持簡單。通常,服務器執行客戶端請求的一些計算。我們也會這樣。我們的服務器將是一個簡單的計算器程序。它只有一種方法:乘法()。它將客戶端程序發送給它的兩個數字相乘,然後返回結果。首先,我們需要一個接口:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
為什麼我們需要接口?因為 RMI 依賴於創建代理,您在過去的課程中學習過。您可能還記得,我們​​通過接口而不是類來使用代理。我們的界面有兩個重要的要求!
  1. 它必須擴展 Remote 接口。
  2. 它的所有方法都必須拋出 RemoteException(IDE 不會自動執行此操作——您需要手動添加!)。
現在我們需要創建一個服務器類來實現我們的計算器接口。 RMI 實踐 - 2在這裡,一切也很簡單:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
這裡真的沒有什麼可評論的:) 現在我們需要編寫一個服務器程序來配置和運行我們的計算器對象。它看起來像這樣:

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

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
讓我們來解決這個問題 :) 在第一行中,我們聲明了一些 String 變量:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
該字符串是遠程對象的唯一名稱。我們的客戶端程序使用這個名稱來查找我們的服務器:您稍後會看到。接下來,我們創建我們的計算器對象:

final RemoteCalculationServer server = new RemoteCalculationServer();
這裡一切都很清楚。接下來的事情更有趣:

final Registry registry = LocateRegistry.createRegistry(2732);
此註冊表對像是遠程對象的註冊表。這些是其他程序可以遠程訪問的對象 :) 我們將數字 2732 傳遞給了LocateRegistry.createRegistry()方法。這是端口號 — 其他程序將使用它來查找我們的對象註冊表的唯一編號(同樣,您將在下面看到)。繼續前進……讓我們看看下一行會發生什麼:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
我們在這一行中創建一個存根。存根封裝了整個遠程調用。您可以認為這是 RMI 最重要的元素。它有什麼作用?
  1. 它接收有關某個方法的遠程調用的所有信息。
  2. 如果該方法有參數,存根將反序列化它們。注意這一點!您傳遞給遠程調用方法的參數必須是可序列化的(畢竟,它們將通過網絡傳輸)。這對我們來說不是問題——我們只是在傳輸數字。但是如果你正在傳輸對象,請不要忘記這個要求!
  3. 之後,存根調用所需的方法。
我們將計算器服務器對像傳遞給UnicastRemoteObject.exportObject()方法。這就是我們如何使遠程調用它的方法成為可能。只剩下一件事要做:

registry.bind(UNIQUE_BINDING_NAME, stub);
我們在遠程對象註冊表中以我們一開始創建的名稱“註冊”我們的存根。現在客戶將能夠找到它!也許你注意到我們在最後讓程序的主線程休眠:

Thread.sleep(Integer.MAX_VALUE);
我們只需要服務器長時間運行即可。在 IDE 中,我們會同時啟動兩個main()方法:首先是服務器的 main() 方法(在我們已經編寫的ServerMain類中),其次是客戶端的 main() 方法(在 ClientMain中,我們將在下面寫)。當我們啟動客戶端時,服務器程序沒有終止是很重要的,所以我們只是讓它休眠了很長時間。無論如何,它將繼續運行 :) 現在我們可以運行服務器的main()方法。讓它運行並等待客戶端程序調用一些方法:) 現在讓我們編寫客戶端程序!它會將數字發送到我們的服務器進行乘法運算。

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

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
看起來很簡單。但是這裡發生了什麼?首先,客戶端必須知道它將遠程調用其方法的對象的唯一名稱。因此,在客戶端程序中,我們創建了public static final String UNIQUE_BINDING_NAME = "server.calculator"; 多變的。 接下來,在main()方法中,我們可以訪問遠程對象的寄存器。為此,我們需要調用LocateRegistry.getRegistry()方法並傳遞用於在 ServerMain 程序中創建註冊表的端口號(端口 2732;此數字只是一個示例——您可以嘗試使用不同的數字):

final Registry registry = LocateRegistry.getRegistry(2732);
現在我們只需要從註冊表中獲取所需的對象!這很容易,因為我們知道它的獨特名稱!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
注意類型轉換。我們將接收到的對象轉換為Calculator接口,而不是RemoteCalculationServer類。正如我們在課程開始時所說的那樣,RMI 依賴於代理,因此遠程調用只能用於接口的方法,不能用於類的方法。最後,我們遠程調用對象的multiply()方法並將結果輸出到控制台。

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMain類的main ()方法已經運行了很長時間。現在是時候在客戶端程序 ( ClientMain ) 中運行main()方法了!控制台輸出:

600
就是這樣!我們的程序(實際上是兩個程序!)做了它應該做的 :) 如果你有時間和願望,你可以稍微增加一點趣味。例如,使計算器支持四種標準算術運算,並且不是將數字作為基本類型傳遞,而是作為CalculationInstance(int x, int y)對像傳遞。下節課見!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION