【Javaの基礎】 - RMIの原理と使い方を詳しく解説
記事ディレクトリ
1.RMIとは何ですか?
RMI : Remote Method Invocation (Remort Method Invocation)。異なるアドレス空間に格納されたプログラムレベルのオブジェクト間の通信をサポートし、リモートオブジェクト間のシームレスなリモート呼び出しを実現します。
JAVA RMI : 異なる仮想マシン間の通信に使用されます。これらの仮想マシンは、異なるホスト上に存在することも、同じホスト上に存在することもできます。ある仮想マシン内のオブジェクトは、別の仮想マシン内のオブジェクトのメソッドを呼び出しますが、許可されているオブジェクトのみが呼び出されます。リモートで呼び出すには、いくつかのフラグで識別する必要があります。
リモート プロシージャ コール(RPC): あるプロセスで別のプロセス (おそらく別のリモート ホスト上) のプロセスを呼び出すために使用でき、これによりプロセス分散機能が提供されます。Java の RMI は、RPC に基づいてさらに一歩前進し、分散オブジェクト間の通信を提供します。
2. RMIの原則
2.1 動作原理図
2.2 動作原理
メソッド呼び出しは、クライアント オブジェクトからスタブ、リモート参照層、トランスポート層を経由してホストに渡され、その後再びトランスポート層を通過し、リモート呼び出し層とバックボーン ネットワーク (スケルトン) を経由してサーバーに到達します。物体。スタブはリモート サーバー オブジェクトのプロキシとして機能し、クライアントがオブジェクトをアクティブ化できるようにします。リモート参照層はセマンティクスを処理し、単一または複数のオブジェクトの通信を管理し、呼び出しを 1 つのサーバーに送信するか複数のサーバーに送信するかを決定します。トランスポート層は実際の接続を管理し、メソッド呼び出しを受け入れることができるリモート オブジェクトを追跡します。サーバー側バックボーンは、サーバー オブジェクトに対する実際のメソッド呼び出しを完了し、戻り値を取得します。戻り値は、リモート参照層とサーバー側のトランスポート層を介してクライアントに戻され、その後、トランスポート層とリモート呼び出し層を介して上向きに返されます。最後に、スタブは戻り値を取得します。
実際、クライアントはリモート ホスト内のオブジェクトを表すスタブ オブジェクトとのみ通信し、サーバーの存在については知りません。クライアントは、スタブ オブジェクトのローカル メソッドを呼び出すだけです。スタブ オブジェクトは、リモート オブジェクトによって公開されるインターフェイスを実装するローカル オブジェクトです。つまり、そのメソッドのシグネチャは、リモート オブジェクトによって公開されるメソッドと同じです。 。クライアントはリモートオブジェクトを呼び出すメソッドだと思っていますが、実際にはStubオブジェクトのメソッドを呼び出しているため、Stubオブジェクトはリモートオブジェクトのローカルプロキシであることがわかります。クライアントがメソッドを呼び出すと、スタブ オブジェクトは、ネットワークを介してリモート オブジェクトに呼び出しを送信します。
3. RMI リモート呼び出し手順
3.1 RMIリモートコール動作フローチャート
3.2 RMI リモート呼び出し手順
- クライアント オブジェクトは、クライアント補助オブジェクト (スタブ) のメソッドを呼び出します。
- クライアント補助オブジェクトは呼び出し情報 (変数、メソッド名) をパッケージ化し、ネットワーク経由でサーバー補助オブジェクトに送信します。
- サーバー補助オブジェクトは、クライアント補助オブジェクトによって送信された情報を解凍して、実際に呼び出されたメソッドとそのメソッドが配置されているオブジェクトを見つけます。
- 実際のサービス オブジェクトで実際のメソッドを呼び出し、結果をサーバー補助オブジェクトに返します。
- サーバー補助オブジェクトは結果をパッケージ化し、クライアント補助オブジェクトに送信します。
- クライアント補助オブジェクトは戻り値を解凍し、クライアント オブジェクトに返します。
- customer オブジェクトは戻り値を取得します
4. JAVA RMIの簡単な実装
4.1 RMI プログラムの実装方法
1). リモート インターフェイスを作成し、java.rmi.Remote インターフェイスを継承します。
2). リモート インターフェイスを実装し、UnicastRemoteObject を継承します。
3). サーバー プログラムを作成します: createRegistry メソッドはリモート オブジェクトを登録し、リスナーを公開します。
4). クライアント プログラムを作成し、IP とポートを介して指定されたサーバーに接続し、データをカプセル化 (シリアル化) します。
5). サーバーはリクエストを受信し、最初にそれを逆シリアル化します。その後、ビジネスロジック処理を実行します。返された結果をシリアル化して返す
4.2 JAVA による RMI プログラムの実装
1). リモートインターフェースを定義する
/**
* 必须继承Remote接口。
* 所有参数和返回类型必须序列化(因为要网络传输)。
* 任意远程对象都必须实现此接口。
* 只有远程接口中指定的方法可以被调用。
*/
public interface IRemoteMath extends Remote {
// 所有方法必须抛出RemoteException
public double add(double a, double b) throws RemoteException;
public double subtract(double a, double b) throws RemoteException;
}
2). リモートインターフェース実装クラス
/**
* 服务器端实现远程接口。
* 必须继承UnicastRemoteObject,以允许JVM创建远程的存根/代理。
*/
public class RemoteMath extends UnicastRemoteObject implements IRemoteMath {
private int numberOfComputations;
protected RemoteMath() throws RemoteException {
numberOfComputations = 0;
}
@Override
public double add(double a, double b) throws RemoteException {
numberOfComputations++;
System.out.println("Number of computations performed so far = "
+ numberOfComputations);
return (a+b);
}
@Override
public double subtract(double a, double b) throws RemoteException {
numberOfComputations++;
System.out.println("Number of computations performed so far = "
+ numberOfComputations);
return (a-b);
}
}
3). サーバー側
/* 注册远程对象,向客户端提供远程对象服务
* 远程对象是在远程服务上创建的,你无法确切地知道远程服务器上的对象的名称
* 但是,将远程对象注册到RMI Service之后,客户端就可以通过RMI Service请求
* 到该远程服务对象的stub了,利用stub代理就可以访问远程服务对象了
*/
public class RMIServer {
public static void main(String[] args) {
try {
IRemoteMath remoteMath = new RemoteMath();
LocateRegistry.createRegistry(1088);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Compute", remoteMath);
System.out.println("Math server ready");
} catch (Exception e) {
e.printStackTrace();
}
}
}
4).クライアント
public class MathClient {
public static void main(String[] args) {
try {
// 如果RMI Registry就在本地机器上,URL就是:rmi://localhost:1088/Compute
// 否则,URL就是:rmi://RMIService_IP:1088/Compute
Registry registry = LocateRegistry.getRegistry("localhost");
// 从Registry中检索远程对象的存根/代理
IRemoteMath remoteMath = (IRemoteMath)registry.lookup("Compute");
// 调用远程对象的方法
double addResult = remoteMath.add(5.0, 3.0);
System.out.println("5.0 + 3.0 = " + addResult);
double subResult = remoteMath.subtract(5.0, 3.0);
System.out.println("5.0 - 3.0 = " + subResult);
}catch(Exception e) {
e.printStackTrace();
}
}
}