目次 前項目 次項目

Java 分散オブジェクトモデル


トピックス:

用語の定義

Java 分散オブジェクトモデルにおいて、リモートオブジェクト とは別な(別なホスト上にあることもある)Java 仮想マシンからそのメソッドを呼び出すことのできるオブジェクトです。 このタイプのオブジェクトは、リモートオブジェクトのメソッドを宣言する Java インタフェースである一つ以上のリモートインタフェースにより記述されます。

リモートメソッド呼び出し (RMI) とはリモートオブジェクト上にあるリモートインタフェースのメソッドを呼び出す操作のことです。このとき最も重要なのはリモートオブジェクトを呼び出すためのシンタックスがローカルオブジェクト呼び出しと同じであることです。

分散モデルと非分散モデルの比較

Java 分散オブジェクトモデルは Java オブジェクトモデルと次の点でよく似ています。

Java 分散オブジェクトは Java オブジェクトモデルと次の点で異なります。

RMI インタフェースとクラス

RMI システムのリモート動作を決定するインタフェースとクラスは java.rmijava.rmi.server パッケージで定義されます。次の図はこれらのインタフェースとクラスの関係を示します。

リモートインタフェース

全てのリモートインタフェースは、直接または間接的に java.rmi.remote インタフェースを拡張します。Remote インタフェースフェースはここに示すように、メソッドを定義しません。

public interface Remote {}
例えば次に示す部分コードは銀行口座へのリモートインタフェースを示したもので、口座預け入れ、収支勘定、引き出しのためのメソッドを含んでいます。

public interface BankAccount
       extends Remote
{
	public void deposit (float amount)
		throws java.rmi.RemoteException;
	public void withdraw (float amount)
		throws OverdrawnException, java.rmi.RemoteException;
	public float balance()
		throws java.rmi.RemoteException;
}
リモートインタフェースのメソッドは次のように定義されなければなりません。

RemoteException クラス

java.rmi.RemoteException クラスは RMI ランタイムがスローすることができる全ての例外のスーパークラスです。RMI システムを使うアプリケーションの安定性を保つために、リモートインタフェースで宣言される各メソッドは throws 節の中で java.rmi.RemoteException を指定しなければなりません。

java.rmi.RemoteException はリモートメソッド呼び出しが失敗(ネットワーキングに失敗した場合や目的とするサーバーへコールが到達しなかったとき)したときにスローされます。これによりリモート呼び出しを実行するアプリケーションはリモート例外にどう対処すればよいかを決定することができます。

RemoteObject クラスとそのサブクラス

RMI サーバー関数は java.rmi.server.RemoteObject とそのサブクラス、java.rmi.server.RemoteServerjava.rmi.server.UnicastRemoteObject が提供します。

リモートインタフェースの実装

リモートインタフェースを実装するクラスの一般則は次のとおりです。

例えば、次に示す部分コードは BankAcctImpl クラスを定義し、その中で BankAccount リモートインタフェースを実装して java.rmi.server.UnicastRemoteObject クラスを拡張しています。:

package my_package;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class BankAccountImpl
        extends UnicastRemoteObject
        implements BankAccount
{
        public void deposit (float amount) throws RemoteException {
                ...
        }
        public void withdraw (float amount) throws OverdrawnException,
                RemoteException {
                ...
        }
        public float balance() throws RemoteException {
                ...
        }
}
必要な場合には、リモートインタフェースを実装するクラスは java.rmi.server.RemoteServer 以外のいくつかのクラスを拡張することもできることに注意してください。 しかし、この場合実装クラスはその Object クラスから継承した hashCodeequals、および toString が正しいリモートセマンティクスに従っていることに対して責任を負わなければなりません。

リモートオブジェクトとローカルスタブにおける型の等価性

分散オブジェクトモデルでは、クライアントはリモートオブジェクトのクラスが定義するのと厳密に同じセットのリモートインタフェースを持ったスタブ(代理)オブジェクトに対して働きかけます。ここで、スタブクラスはオブジェクトの型グラフを構成するクラス階層の非リモート部分を含みません。 この理由はスタブクラスは一つ以上のリモートインタフェースを実装する最も詳細な (具体化された) 実装クラスから生成されるからです。 例えば、もし C が B を拡張し、B が A を拡張したとして、B だけがリモートインタフェースを実装するならば、スタブが生成されるのは B からであり、C からではありません。

スタブはリモートオブジェクトクラスと同じセットのリモートインタフェースを実装しますから、Java システム側から見ると、スタブはサーバーオブジェクトの型グラフのリモート部分と同じ型を持つことになります。従って、クライアントは Java の組み込み演算によってリモートオブジェクトの型チェックをおこない、一つのリモートインタフェースから別なインタフェースへのキャストを行うことができます。

スタブは rmic コンパイラにより作成されます。

リモートメソッド呼出しでのパラメーター引き渡し

リモートオブジェクトへ渡す引数および返り値は Java の持つ型ならばどれでも可能です、つまり直列化できます。 これには Java のプリミティブ型、リモート Java オブジェクト、 java.io.Serializable インタフェースを実装した非リモート Java オブジェクトが含まれます。 クラスを直列化可能にする方法の詳細については Java の「オブジェクト直列化仕様 (Object Serialization Specification)」を参照してください。アプレットの場合には、引数や返り値のクラスがローカルには得られないときは AppletClassLoader によって動的にロードされます。 アプリケーションの場合には、これらのクラスはアプリケーションをロードしたクラスローダーにより行われます。このクラスローダーはデフォルトクラスローダー(ローカルなクラスパスを用いる)か RMIClassLoader(サーバーの codebase を用いる)のいずれかです。

いくつかのクラスは、例えばセキュリティ上の理由により、(直列化ができないため)渡されるのが禁止されます。 この場合にはリモートメソッド呼び出しは例外発生により失敗します。

非リモートオブジェクトの引き渡し

リモートメソッド呼び出しの引数、および呼び出しの結果戻される返り値としての非リモートオブジェクトはコピーにより渡されます。

つまり、非リモートオブジェクトがリモートメソッド呼び出しに現れると、非リモートオブジェクトの内容はリモートオブジェクトの呼び出しがコールされる前にコピーされます。デフォルトでは static ではなく、transient でないフィールドだけがコピーの対象になります。

同様にして、リモートメソッド呼び出しから非リモートオブジェクトが戻されるときは、呼び出し側の仮想マシンに新規オブジェクトが作成されます。

リモートオブジェクトの引き渡し

リモートオブジェクトをパラメーターとして渡す場合には、そのリモートオブジェクトのスタブが渡されます。パラメーターとして渡されたリモートオブジェクトはリモートインタフェースのみを実装することができます。

リモートメソッド呼び出しにおける例外処理

リモートメソッドはそのシグネチャの中に java.rmi.RemoteException を含むため、呼び出し側はアプリケーションに固有の例外に加えてこれに備えておく必要があります。 リモートメソッド呼び出し中に java.rmi.RemoteException がスローされたとき、クライアント側には呼び出しの結果、エラーが発生するのは呼び出しの前なのか、実行中なのか、呼び出し完了後なのか等々についての情報がないかもしれません。 このため、リモートインタフェースとその中で宣言される呼び出し側メソッドはこれらのエラーに関するセマンティクスに留意して設計するべきです。

RemoteObject クラスによる Object メソッドオーバーライド

Object クラスのデフォルト実装による equalshashCode、および toString メソッドはリモートオブジェクトに対して適切ではありません。 このため、java.rmi.server.RemoteObject クラスがこれらのメソッドに対するリモートオブジェクトに適したセマンティクスの実装を提供しています。 この方法により、リモートから利用できなければならない全てのオブジェクトは java.rmi.server.RemoteObject を拡張することができます(典型的には java.rmi.server.UnicastRemoteObject を介して間接的に拡張します)。

equals と hashCode

リモートオブジェクトをハッシュテーブルのキーとして使えるようにするため、メソッド equalshashCodejava.rmi.server.RemoteObject クラスでオーバーライドされます。

toString

toString メソッドはオブジェクトへの参照を表現した文字列を返すために定義されています。 文字列の内容は参照のタイプに固有のものです。 singleton (ユニキャスト) オブジェクトの現在の実装はトランスポートレイヤに固有なオブジェクトの情報(ホスト名やポート番号)とオブジェクト識別子を含みます。複製オブジェクトへの参照はさらに多くの情報を含みます。

クローン

Java 言語のデフォルト機構を使ってのオブジェクトのクローン生成は、オブジェクトが java.lang.Cloneable インタフェースをサポートしているときのみ可能です。リモートオブジェクトはこのインタフェースを実装しませんが、 clone メソッドは実装していますからサブクラスが Cloneable を実装する必要があるならばリモートクラスは正しく動作します。

クライアントスタブは final として宣言され、 clone を実装しません。 このためスタブのクローン生成はローカルな操作であり、クライアントが新規にリモートオブジェクトを生成するために使うことはできません。

finalize

リモートオブジェクトの実装(RemoteObject のサブクラス)は必要に応じて自分自身のクリーンアップのために finalize を使うことができます。例えば、 finalize を使ってオブジェクトサーバーを不活性化することができます。

ファイナル宣言された Object メソッドのセマンティクス

以下のメソッドは Object クラスにおいて final 宣言され、オーバーライドはできません:

getClass のデフォルト実装は全て(ローカルとリモート両方)の Java オブジェクトに適用可能です。 リモートオブジェクトに使われた場合には、getClass メソッドが生成されたスタブオブジェクトの正確な型をレポートしてくれます。 ただし、この型はオブジェクトにより実装されたリモートインタフェースのみを反映したもので、そのローカルインタフェースではないことに注意してください。

Object の waitnotify メソッドは Java 言語のスレッドモデルに即して待ちと通知を取り扱います。これらのメソッドをリモートオブジェクトに対して使うのは Java のスレッドモデルに違反する訳ではありませんが、これらのメソッドはローカルな Java オブジェクトを扱う場合とはセマンティクスが異なります。 特に、これらのメソッドはクライアントのリモートオブジェクト(スタブ)に対するローカルな参照に作用し、リモートにある実際のオブジェクトに作用する訳ではありません。

リモートオブジェクトの位置決め

単純ブートストラップ名前サーバーがリモートオブジェクトに対する名前付き参照を保存するために準備されています。 リモートオブジェクト参照は java.rmi.Naming クラスの URL をベースとするメソッドを使って保存することができます。

クライアントがリモートオブジェクトのメソッドを呼び出すときには、クライアントはまずそのオブジェクトに対する参照を得る必要があります。 リモートオブジェクトに対する参照は通常メソッドコールの返り値として得られます。 RMI システムは単純ブートストラップネームサーバーを提供して指定されたホストのリモートオブジェクトを得られるようにしています。 java.rmi.Naming クラスは URL(Uniform Resource Lacator) ベースのメソッドを提供して特定のホストとポートにおける名前-オブジェクト対のルックアップ、バインド、リバインド、アンバインドそしてリストを可能にしています。

次に示すのは、リモートオブジェクトのルックアップとバインドを実行する例です(例外処理は省略)。

BankAccount acct = new BankAcctImpl();
String url = "rmi://java.Sun.COM/account";
// bind url to remote object
java.rmi.Naming.bind(url, acct);
	...
// lookup account
acct = (BankAccount)java.rmi.Naming.lookup(url);


目次 前項目 次項目

Copyright (C) 1996, 1997 Sun Microsystems, Inc. All rights reserved.