すべてのコンポーネントが同じコンピュータ上の同じ Java 仮想マシンの同じヒープ領域で実行されれば最も簡単ですが、実際には、クライアントが Java を実行できる単なるデバイスである場合、そのような単一の状況に直面することはよくありません。する?セキュリティ上の理由から、サーバー上のプログラムのみがデータベースにアクセスできる場合はどうなるでしょうか?
ほとんどの場合、メソッド呼び出しは同じヒープ上の 2 つのオブジェクト間で発生することがわかっていますが、異なるマシン上のオブジェクトのメソッドを呼び出したい場合はどうすればよいでしょうか。
通常、ソケットの入出力ストリームを通じてあるコンピューターから別のコンピューターに情報を取得し、他のコンピューターのソケット接続を開き、outputStream を取得してデータを書き込みます。しかし、別のコンピューターを呼び出す場合は、コンピュータ、別の Java 仮想マシン上のオブジェクトのメソッドは何ですか?もちろん、呼び出す通信プロトコルを自分で定義および設計し、実行結果を Socket 経由で送信することもできます。また、ローカル マシン上のメソッドを呼び出すこともできます。つまり、リモート オブジェクト (たとえば、他のヒープと同様) ) ですが、これは通常の呼び出しと同様であるはずです。
これが RMI が私たちにもたらすものです。
リモート プロシージャ コールの設計
作成するものは、サーバ、クライアント、サーバ補助機能、クライアント補助機能の4つです。
1. クライアント アプリケーションとサーバー アプリケーションを作成します。サーバー アプリケーションはリモート サービスであり、クライアントが呼び出すメソッドを持つオブジェクトです。
2. クライアント側とサーバー側のヘルパーを作成します。これらのヘルパーは、クライアントとサーバーの基礎となるネットワーク入出力の詳細をすべて処理し、クライアントとプログラムがローカル呼び出しを処理しているように見せます。
補助機能のタスク 補助機能は、クライアントにローカル オブジェクトを呼び出しているように見えますが、実際にはメソッド A を呼び出しているだけです。サーバー側でソケットとストリーミングの詳細をローカルに処理するプロキシ。サーバーの補助機能がソケットを介してクライアント機能からのリクエストを接続し、パッケージ化された情報を解析して実際のサービスを呼び出します。したがって、サービス オブジェクトの場合、これは After になります。ローカル サービスから補助機能を呼び出すと、戻り値を取得し、それをラップしてクライアントの補助機能に送り返します。クライアントの補助機能は、情報を解凍してクライアント オブジェクトに送信します。
メソッドを呼び出すプロセス
1. クライアント オブジェクトは、補助機能オブジェクトに対して doBigThing() を呼び出します。
2. クライアントの補助設備は通話情報をパッケージ化し、ネットワークを通じてサーバーの補助設備に送信します。
3. サーバー側の補助機能は、クライアント側の補助機能からの情報をデコードし、それを使用して実際のサービスを呼び出します。
このプロセスを説明する図は次のとおりです。
JavaRMI はクライアント側とサーバー側のヘルパー オブジェクトを提供します
Java では、RMI はクライアント側とサーバー側の補助機能を作成するのに役立ちました。また、RMI はクライアント側の補助機能を実際のサービスのように見せる方法も知っています。つまり、RMI はクライアント呼び出しに同じメソッドを提供する方法も知っています。 。
さらに、RMI は、クライアントがクライアント (リアル サービス エージェント) を見つけて取得できるようにするサービス クエリや補助機能など、実行に必要なすべてのインフラストラクチャを提供します。
RMI を使用する場合、ネットワークまたは入出力プログラムを作成する必要はありません。クライアントによるリモート メソッドの呼び出しは、同じ Java 仮想マシン上のメソッド呼び出しと同じです。
一般的な呼び出しは RMI 呼び出しとは少し異なりますが、クライアントにとってはこのメソッド呼び出しはローカルに見えますが、この呼び出しは最終的にはソケットとストリームを介して行われます。中間情報が Java 仮想マシンから Java 仮想マシンにどのように送信されるかは、補助機能オブジェクトによって使用されるプロトコルによって異なります。
RMI を使用する場合、JRMP または IIOP のどちらのプロトコルを選択する必要があります。JRMP は Java 間のリモート呼び出し用に設計されており、これにより Java を呼び出すことができます。オブジェクトやその他の種類のリモート メソッドの場合、CORBA は通常、RMI よりも面倒です。両端が Java でない場合、大量のひどい変換操作や会話操作が発生するためです。
ここでは Java 間の操作のみを考慮しているため、非常に単純な RMI を使用します。
RMIでは、クライアント側の補助機能をスタブ、サーバー側の補助機能をスケルトンと呼びます。
リモートサービスの作成方法
1.リモートインターフェースの作成
リモート インターフェイスは、クライアントがリモートで呼び出すことができるメソッドを定義します。これは、スタブとサービスの両方がこのインターフェイスを実装するサービスとしての多態性クラスです。
2. リモートインターフェイスの実装
これは、インターフェイス上で定義されたメソッドを実装する実際の実行クラスです。クライアントが呼び出すオブジェクトです。
3. rmic を使用してスタブとスケルトンを生成する
クライアントとサーバーの両方にヘルパーがあります。これらのクラスを作成したり、これらのクラスのソース コードを生成したりする必要はありません。これは、JDK に付属の rmic ツールを実行するときに自動的に処理されます。
4. RMIregistry (rmiregistry) を起動します。
rmiregistry は電話帳のようなもので、ユーザーはここからプロキシ (クライアントのスタブ/ヘルパー オブジェクト) を取得します。
5. リモートサービスを開始する
サービス オブジェクトは実行を開始する必要があります。サービスを実装するクラスはサービス インスタンスを開始し、登録後にのみサービスをユーザーに提供できます。
サーバーコード
インターフェースの定義
/**
*
*MyRemote.java
*
* 機能: TODO
* クラス名:MyRemote.java
*
* キャラクターホルダーと新しいコンテンツを更新しました。
※─────────────────
* V1.00 2013-3-19 モジュール Su Ruo の最初のバージョン
*
* Copyright (c) 2013 デニシットコーポレーション All Rights Reserved.
*
* 電子メール:<a href="mailto:[email protected]">電子メールを送信</a>
*
*
* リモートはマークされたインターフェイスであり、メソッドが存在しないことを意味します。ただし、RMI にとって特別な意味があるため、このルールに従う必要があります。
* ここでは extends が使用されており、インターフェイスは他のインターフェイスを継承できることに注意してください。
*
*/
パブリック インターフェイス MyRemote は Remote{ を拡張します
/**
* リモート インターフェイスは、クライアントがリモートで呼び出すことができるメソッドを定義します。つまり、クライアントがサービスとして呼び出すことができます。
※このインターフェースを実装するスタブを動員し、このスタブがネットワークや入出力の作業を行うため、様々なことが起こる可能性があります
* 問題は、クライアントがこのタイプのリスクを認識するために例外を処理または宣言する場合、メソッドがインターフェイスで例外を宣言する場合、そのメソッドを呼び出すことです。
* すべてのプロシージャは、この例外を処理するか再宣言する必要があります。
*
* リモート メソッドのパラメータと戻り値はプリミティブまたはシリアル化可能である必要があります。
※パッケージはネットワーク経由で送信され、シリアル化を経て完了した場合の戻り値はカスタム型を使用した場合と同じになります。
*、シリアル化する必要があります
* @戻る
* @throws RemoteException
* インターフェース内のすべてのメソッドは RemoteException を宣言する必要があります
*/
public String SayHello() は RemoteException をスローします。
}
/**
*
*MyRemoteImpl.java
*
* 機能: TODO
* クラス名:MyRemoteImpl.java
*
* キャラクターホルダーと新しいコンテンツを更新しました。
※─────────────────
* V1.00 2013-3-19 モジュール Su Ruo の最初のバージョン
*
* Copyright (c) 2013 デニシットコーポレーション All Rights Reserved.
*
* 電子メール:<a href="mailto:[email protected]">電子メールを送信</a>
*
* リモート サービス オブジェクトになるためには、オブジェクトにリモート関連の機能が必要です。最も簡単な方法は、UnicastRemoteObject を継承することです。
* (java.rmi.server から) この親クラスに作業を処理させる
*
*/
public class MyRemoteImpl extends UnicastRemoteObjectimplements MyRemote{
/**
* 親クラスのコンストラクターは例外を宣言するため、コンストラクターを作成する必要があります。これは、コンストラクターが危険なプログラム コードを呼び出すことを意味するためです。
*
* UnicastRemoteObject には小さな問題があり、そのコンストラクターは RemoteException をスローします。これを処理する唯一の方法があります。
* 独自の実装のコンストラクターを宣言して、クラスが初期化されるときに親クラスである RemoteException を宣言する場所を確保します。
* コンストラクターは必ず呼び出されます。親クラスのコンストラクターが例外をスローする場合、宣言する必要があるカスタム コンストラクターも例外をスローします。
* @throws RemoteException
*/
protected MyRemoteImpl() は RemoteException をスローします {
}
/**
* 発信インターフェースのすべてのメソッドを実装しますが、RemoteException を宣言する必要はありません
*/
@オーバーライド
パブリック文字列sayHello(){
return "サーバーは、rmi hello world!" を返します。
}
public static void main(String[] args) {
試す {
/**
* すでにリモート サービスがあり、リモート ユーザーがそのサービスにアクセスできるようにする必要があります。これを行うには、サービスを初期化し、RMI レジストリに追加します。
* (実行している必要があります。実行していないと、このプログラムは失敗します)。オブジェクトを登録するとき、RMI システムはスタブをレジストリに追加します。
※これはクライアントが必要とするため、java.rmi.Naming の rebind() を使用してサービスを登録します。
*/
MyRemote サービス = new MyRemoteImpl();
/**
* リモート オブジェクトを作成し、静的な Naming.rebind() を使用して関連付けを作成します。登録された名前はクライアント クエリに提供されます。
*/
Naming.rebind("リモート Hello World", サービス);
} catch (例外 e) {
e.printStackTrace();
}
}
}
public void exec(){
試す {
/**
* クライアントは、そのメソッドを呼び出す必要があるため、スタブ オブジェクトを取得する必要があります。これは、クライアントが電話機に次のようにクエリするためです。
* 同じディレクトリを検索して、名前が一致するサービスを見つけます。
* クライアントは RMIRegistry にクエリを実行し、スタブ オブジェクトを返します。
* Naming.lookup("rmi://127.0.0.1/Remote Hello World");
* パラメータの説明
* rmi://127.0.0.1/Remote Hello World
* 127.0.0.1 はホスト名またはホスト IP アドレスを表します
※リモートHello Worldは登録名と同じである必要があります
*
*/
MyRemote サービス = (MyRemote)Naming.lookup("rmi://127.0.0.1/Remote Hello World");
文字列 tmp = service.sayHello();
System.out.println(tmp);
} catch (例外 e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
新しい MyRemoteClient().exec();
}
}
JDK に付属の rmic ツールは、サービス実装に基づいて 2 つのクラス (スタブとスケルトン) を生成し、命名規則に従ってリモート実装名の後に _Stub または _Skeleton を追加します。 rmic には、スケルトンを生成しない、生成されたクラスのソース コードを監視する、または生成されたクラスが現在のディレクトリに配置されるなど、いくつかのオプションがあります。したがって、実装が配置されているディレクトリから rmic を実行する必要がある場合があります (実際には、パッケージのディレクトリ構造と完全な名前を考慮する必要がある場合があります。簡単にするために、ここではパッケージは使用しません)。
rmiregistry を起動するには、コマンド ラインを呼び出します。クラスにアクセスできるディレクトリから起動するのが最も簡単な方法です。
実行中のスクリーンショットは次のとおりです
知らせ:
クライアントはインターフェイスを使用してスタブ上のメソッドを呼び出します。クライアントの Java 仮想マシンにはスタブ クラスが必要ですが、クライアントは常にインターフェイスを通じて実際のリモート オブジェクトを操作します。
サーバーには、サービスとリモート インターフェイスだけでなく、スタブとスケルトンも必要です。スタブは RMIRegistry に接続されている実際のサービスに置き換えられるため、スタブ クラスが必要です。
RMI を使用するときによくある間違い:
1. リモートサービスを開始する前に rmiregistry を開始するのを忘れました (Naming.rebind() を使用してサービスを登録する前に rmiregistry を開始する必要があります)
2. パラメーターと戻り値の型をシリアル化可能にするのを忘れました (コンパイル中には検出されず、実行中にのみ検出されます)
3. スタブクラスをクライアントに引き渡すのを忘れる
RMI はリモート サービスの作成と実行には非常に適していますが、大規模なエンタープライズ レベルのアプリケーションの実行には RMI だけを使用するわけではなく、トランザクション管理、大規模な同時処理など、より優れた機能が必要になります。これには、EnterpriseApplicationServer の使用が必要です。
JavaEE サーバーには、Web サーバーと Enterprise JavaBeans (EJB) サーバーが含まれます。EJB サーバーは、RMI 呼び出しとサービス層の間で機能します。
JINI における RMI の適用
Jini も RMI を使用しますが (他のプロトコルも使用できます)、さらにいくつかの重要な機能があります。
1. アダプティブディスカバリー
2. 自己修復ネットワーク
RMI クライアントは、まずリモート サービスのアドレスと名前を取得する必要があります。クライアントのクエリ プログラム コードには、リモート サービスの IP アドレスまたはホスト名 (RMIRegistry があるため) と、サービスによって登録された名前が含まれている必要があります。
しかし、JINI を使用する場合、ユーザーが知っておく必要があるのは 1 つのことだけです。それは、サービスによって実装されたインターフェイスです。
Jini は、RMIRegistry よりも強力で適応性のある lookupservice を使用します。これは、クエリ サービスがオンラインになると、IP マルチキャスト テクノロジを使用して、クライアントがネットワーク全体に情報を送信するためです。クエリ サービスがブロードキャストされた後にオンラインになり、クライアントはネットワーク全体にメッセージを送信して問い合わせることもできます。
サービスは、オンラインになると、ネットワーク上の JINI クエリ サービスを動的に探索し、登録時にシリアル化されたオブジェクトをクエリ サービスに送信します。このオブジェクトは、RMI リモート サービスのスタブである場合があります。ネットワークデバイスのドライバー、またはクライアント上で実行できるサービス自体の名前ではありません。
適応型探索の仕組み
1.Jini クエリ サービスはネットワーク上で開始され、IP マルチキャスト テクノロジを使用して自身を宣伝します。
2. 開始された別の Jini サービスは、新しく開始されたクエリ サービスへの登録を試みます。名前ではなく関数、つまり実装されたインターフェイスを登録し、シリアル化されたオブジェクトをクエリ サービスに送信します。
3. インターネット顧客は、ScientificCalculator を実装するために何かを入手したいと考えていますが、どこで見つけられるかわからないため、クエリ サービスに問い合わせます。
4. クエリ サービスがクエリ結果に応答する
自己修復ネットワークの運用
1. 特定の Jini サービスには登録が必要であり、新しく登録されたサービスはリースを定期的に更新する必要があります。そうでない場合、クエリ サービスはサービスがオフラインであると想定します。利用可能なサービス ネットワークのステータスが完了しました。
2. サービスはシャットダウンによりオフラインになっているため、リースは更新されず、クエリ サービスが開始されます。