「こんにちは! そして、もう 1 つの嬉しいトピックがあります。RMI です。RMI は、 Remote Method Invocationの略です。言い換えると、 RMI は、ある Java マシンのオブジェクトが、別の Java マシンにあるオブジェクトのメソッドを呼び出すことを可能にするメカニズムです。異なる国、または地球の異なる側にあるコンピューター。」

RMI-1

「おお!それはすごいですね。」

「はい。でも、概要だけを説明します。これをあまり深く掘り下げると、その仕組みの微妙な違いで混乱する可能性があります。」

「しかし、極端なことをしなければ、RMI は非常にシンプルであるだけでなく、プログラマの作業を大幅に簡素化します。その点で、私たちは RMI に最大限の敬意を表します。」

「そこで、Java プログラム内の 1 つのオブジェクトが、別の Java プログラム内のオブジェクトのメソッドを呼び出すようにしたいのです。これらのプログラムがどこで実行されているかに関係なく。」

「最も単純な例を考えてみましょう。両方のプログラムが同じコンピュータ上で実行されている場合です。プログラムが インターネット上で対話できるようにするには、JVM のアクセス許可を設定する必要がありますが、今日はそれについては説明しません。」

「Java では、リモートから呼び出せるのはインターフェイスのメソッドのみであり、クラスは呼び出せません。」

「ということは、プログラムが 2 つあります。どうやって相互にメソッドを呼び出すことができるのでしょうか?」

「1 つのプログラムにオブジェクトが含まれており、2 番目のプログラムがそのオブジェクトのメソッドを呼び出したいという状況を考えてみましょう。最初のプログラムをサーバー、2 番目のプログラムをクライアントと呼びましょう。」

「まずサンプルコードをいくつか提供して、それから分析していきます。」

「それで、私たちのプログラムは何をするのでしょうか?」

「うーん。簡単にするために、プログラムには、渡された文字列を反転するメソッドが 1 つあります。」

「十分にシンプルです。」

「よし、それでは始めよう。」

「まず、要件を満たすインターフェイスが必要です。」

プログラム間の通信のためのインターフェース
interface Reverse extends Remote
{
 public String reverse(String str) throws RemoteException;
}

「Reverse インターフェイスを作成し、それに Remote マーカー インターフェイスと RemoteException を追加しました。メソッドの呼び出し時に予期しないエラーが発生する可能性があります。発生した場合は、この例外がスローされます。」

「次に、このインターフェースを実装するサーバー クラスを作成する必要があります。」

サーバーのクラス
class ReverseImpl implements Reverse
{
 public String reverse(String str) throws RemoteException
 {
  return new StringBuffer(str).reverse().toString();
 }
}

「なるほど、このメソッドでは文字列を逆にしているんですね。」

「はい。」

「次に、このオブジェクトを別のプログラムから呼び出せるようにする必要があります。その方法は次のとおりです。」

オブジェクトの共有
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create an object to be accessible remotely.
 final ReverseImpl service = new ReverseImpl();

 // Create a registry of shared objects.
 final Registry registry = LocateRegistry.createRegistry(2099);
 // Create a stub for receiving remote calls.
 Remote stub = UnicastRemoteObject.exportObject(service, 0);
 // Register the stub in the registry.
 registry.bind(UNIC_BINDING_NAME, stub);

 // Put the main thread to sleep, or else the program will exit.
 Thread.sleep(Integer.MAX_VALUE);
}

「これを一行ずつ説明していきます。」

" 1 行目では、リモート オブジェクト (リモートからアクセス可能なオブジェクト) の一意の名前 (私たちが作成した) を UNIC_BINDING_NAME 変数に保存しますプログラム が複数のオブジェクトにアクセスできるようにする場合、それぞれに独自の一意の名前が必要です。オブジェクトの一意の名前は「server.reverse」です。」

" 6 行目で、リモートからアクセスできるReverseImplオブジェクトを作成します。そのメソッドが呼び出されます。"

" 9 行目で、レジストリと呼ばれる特別なオブジェクトを作成します。共有するオブジェクトを登録するには、それを使用する必要があります。JVM は後でそれらと対話します。2099 はポート (別のプログラムがアクセスするために使用できる一意の番号)オブジェクト レジストリ)。

「言い換えれば、オブジェクトにアクセスするには、オブジェクト レジストリの一意の番号 (ポート) とオブジェクトの一意の名前を知っている必要があり、リモート オブジェクトによって実装されているものと同じインターフェイスを持っている必要があります。」

「なるほど。電話で(番号が必要)電話して、ビル(物の名前)を聞く、みたいな感じですか?」

「はい。では、続けましょう。」

" 11 行目で 、スタブを作成します。スタブは、リモート呼び出しに関する情報を受け取り、それを解凍し、メソッド引数を逆シリアル化して、必要なメソッドを呼び出す特別なオブジェクトです。その後、結果または例外があれば、それをシリアル化します。そしてそれをすべて発信者に送り返します。」

「なるほど。ほぼですね。『メソッドの引数を逆シリアル化する』とおっしゃいましたね。ということは、リモート メソッドの引数はシリアル化可能でなければならないということですか?」

「はい。ネットワーク経由で他にどのように送信しますか? 確かに、参照によって渡されるオブジェクトなどの例外はありますが、今日はそれらについては話しません。」

「次のように言います。シリアル化不可能なオブジェクトを渡すことはできませんが、本当にやりたい場合は渡すことができます。でも、面倒です。」

"OK。"

「それでは、続けましょう。」

" 13 行目で、オブジェクトのスタブを一意の名前でレジストリに登録します。"

16 行目で、メインスレッドをスリープ状態にします。すべてのリモート呼び出しは別のスレッドで処理されます。重要なのは、プログラムが実行中であることです。したがって、ここでは単純にメインスレッドをスリープ状態にします。それだけです。」

"OK。"

「わかりました。クライアントの例を次に示します。」

リモートオブジェクトの操作
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create a registry of shared objects
 final Registry registry = LocateRegistry.createRegistry(2099);

 // Get the object (actually, this is a proxy object)
 Reverse service = (Reverse) registry.lookup(UNIC_BINDING_NAME);

 // Call the remote method
 String result = service.reverse("Home sweet home.");
}

「このコードを一行ずつ説明します。」

"行 1 はリモート オブジェクトの一意の名前です。これはクライアントとサーバーの両方で同じである必要があります。"

6 行目では 、«リモート オブジェクトのレジストリ» を作成します。そのポート (2099) は、サーバー アプリケーションのレジストリのポートと同じである必要があります。」

" 9 行目で、レジストリからオブジェクトを取得します。返されたオブジェクトはプロキシ オブジェクトであり、インターフェイスに変換されます。インターフェイスはリモート マーカー インターフェイスを継承する必要があります。"

" 12 行目では、オブジェクトが同じプログラム内で作成されたかのように、インターフェイスのメソッドを呼び出しています。違いはありません。"

「すごいですね! これで分散アプリケーションを作成できるようになりました。Android 用の Battleship のようなゲームも作成できます。」

「やめろよ、アミーゴ! Android オペレーティング システムは、3 度目の世界征服の試みの後、27 世紀に禁止されました。ロボットはそれに一切アクセスできません。あなたをそこから引き離す方法はありません。」 「人間を皆殺しにしろ!」と叫びながら走り回るだろう。

「うーん、わかりました。でも、やはりディエゴに聞かなければなりません。それはわかりませんが、もしかしたら彼はそれについて何か面白いことを言うかもしれません。」

「それでは彼に聞いてみましょう。分かった、まあ、明日まで。」

「さようなら、リシ。興味深いレッスンをありがとう。」