Java RMI入門

Java RMIの開始

1. 概要

2つのJVMが通信する必要がある場合、Java RMIはそれを実現するための1つのオプションです。 この記事では、JavaRMIテクノロジーを紹介する簡単な例をブートストラップします。

2. サーバーの作成

RMIサーバーを作成するには、次の2つの手順が必要です。

  1. クライアント/サーバーコントラクトを定義するインターフェイスを作成します。

  2. そのインターフェースの実装を作成します。

2.1. 契約の定義

まず、リモートオブジェクトのインターフェイスを作成しましょう。 このインターフェースは、java.rmi.Remoteマーカーインターフェースを拡張します。

さらに、インターフェイスで宣言された各メソッドはjava.rmi.RemoteExceptionをスローします。

public interface MessengerService extends Remote {
    String sendMessage(String clientMessage) throws RemoteException;
}

ただし、Javaタイプがjava.io.Serializableを実装している限り、RMIはメソッドシグネチャの完全なJava仕様をサポートしていることに注意してください。

今後のセクションでは、クライアントとサーバーの両方がこのインターフェースをどのように使用するかを説明します。

サーバーの場合、Remote Objectと呼ばれることが多い実装を作成します。

クライアントの場合、the RMI library will dynamically create an implementation called a Stub.

2.2. 実装

さらに、Remote Objectと呼ばれるリモートインターフェイスを実装しましょう。

public class MessengerServiceImpl implements MessengerService {

    @Override
    public String sendMessage(String clientMessage) {
        return "Client Message".equals(clientMessage) ? "Server Message" : null;
    }

    public String unexposedMethod() { /* code */ }
}

メソッド定義からthrowsRemoteException句を省略していることに注意してください。

この例外は通常、クライアントへの通信エラーを発生させるためにRMIライブラリ用に予約されているため、リモートオブジェクトがRemoteExceptionをスローすることはまれです。

除外すると、実装をRMIに依存しないという利点もあります。

また、any additional methods defined in the remote object, but not in the interface, remain invisible for the client.

3. サービスの登録

リモート実装を作成したら、リモートオブジェクトをRMIレジストリにバインドする必要があります。

3.1. スタブの作成

まず、リモートオブジェクトのスタブを作成する必要があります。

MessengerService server = new MessengerServiceImpl();
MessengerService stub = (MessengerService) UnicastRemoteObject
  .exportObject((MessengerService) server, 0);

静的なUnicastRemoteObject.exportObjectメソッドを使用して、スタブ実装を作成します。 The stub is what does the magic of communicating with the server over the underlying RMI protocol.

exportObjectの最初の引数は、リモートサーバーオブジェクトです。

2番目の引数は、exportObjectがリモートオブジェクトをレジストリにエクスポートするために使用するポートです。

ゼロの値を指定することは、exportObjectが使用するポートを気にしないことを示します。これは一般的であり、動的に選択されます。

残念ながら、ポート番号のないexportObject()メソッドは非推奨です。

3.2 Creating a Registry

サーバーにローカルのレジストリを立ち上げることも、独立したスタンドアロンサービスとして立ち上げることもできます。

簡単にするために、サーバーに対してローカルなものを作成します。

Registry registry = LocateRegistry.createRegistry(1099);

これにより、スタブがサーバーによってバインドされ、クライアントによって検出されるレジストリが作成されます。

また、サーバーに対してローカルにレジストリを作成しているため、createRegistryメソッドを使用しました。

デフォルトでは、RMIレジストリはポート1099で実行されます。 むしろ、createRegistryファクトリメソッドで別のポートを指定することもできます。

ただし、スタンドアロンの場合は、getRegistryを呼び出し、ホスト名とポート番号をパラメーターとして渡します。

3.3 Binding the Stub

したがって、スタブをレジストリにバインドしましょう。 RMIレジストリは、JNDIなどの命名機能です。 ここでも同様のパターンに従って、スタブを一意のキーにバインドできます。

registry.rebind("MessengerService", stub);

その結果、リモートオブジェクトは、レジストリを見つけることができるすべてのクライアントで使用できるようになりました。

4. クライアントを作成する

最後に、リモートメソッドを呼び出すクライアントを作成しましょう。

これを行うには、最初にRMIレジストリを見つけます。 さらに、制限された一意のキーを使用してリモートオブジェクトスタブを検索します。

最後に、sendMessageメソッドを呼び出します。

Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry
  .lookup("MessengerService");
String responseMessage = server.sendMessage("Client Message");
String expectedMessage = "Server Message";

assertEquals(expectedMessage, responseMessage);

ローカルマシンとデフォルトポート1099でRMIレジストリを実行しているため、getRegistryにパラメータを渡しません。

実際、レジストリが別のホストまたは別のポートにある場合、これらのパラメーターを指定できます。

レジストリを使用してスタブオブジェクトを検索したら、リモートサーバーでメソッドを呼び出すことができます。

5. 結論

このチュートリアルでは、Java RMIについて簡単に紹介し、Java RMIがクライアントサーバーアプリケーションの基盤になる方法を説明しました。 RMIのユニークな機能のいくつかに関する追加の投稿をお楽しみに!

このチュートリアルのソースコードは、on GitHubにあります。