S
- このローダーによってロードされるサービスのタイプpublic final class ServiceLoader<S> extends Object implements Iterable<S>
サービスとは、既知のインタフェースおよびクラス(通常は抽象クラス)のセットです。サービス・プロバイダとは、特定のサービスの実装です。通常、プロバイダのクラスによって、サービス自体に定義されているクラスのインタフェースとサブクラスが実装されます。サービス・プロバイダをJavaプラットフォームの実装にインストールするときは、拡張機能の形式、つまり、拡張機能の通常のディレクトリに配置されるjarファイルの形式で行われます。プロバイダを利用可能にするには、アプリケーションのクラス・パスに追加するか、プラットフォーム固有の方法を使います。
サービスはロード目的のために、単一の型、つまり単一のインタフェースまたは抽象クラスとして表現されます。(具象クラスも使用できますが、それはお薦めできません。)特定のサービスのプロバイダには、このサービス・タイプをプロバイダに固有のデータやコードで拡張した、1つ以上の具象クラスが含まれています。通常、プロバイダ・クラスには、プロバイダ自体がすべて含まれることはありません。要求時に実際のプロバイダを作成できるコードとともに、プロバイダが特定の要求を満たすことができるかどうかを識別するために必要な情報で構成されるプロキシになっています。プロバイダ・クラスの内容は、個別のサービスに大きく依存します。1つのクラスまたはインタフェースでプロバイダ・クラスを統合することはできません。このため、このような型はここでは定義されていません。この機能が強制する唯一の要求は、プロバイダ・クラスには、ロード中にインスタンスを生成できるように、引数を取らないコンストラクタが存在しなければいけない、ということです。
サービス・プロバイダは、リソース・ディレクトリMETA-INF/servicesにプロバイダ構成ファイルを配置することによって識別されます。ファイルの名前は、サービスのタイプの完全指定バイナリ名です。このファイルには、具象プロバイダ・クラスの完全指定バイナリ名が1行に1つずつ記述されます。それぞれの名前を囲む空白文字とタブ文字、および空白行は無視されます。コメント文字は'#' ('\u0023'、番号記号)です。各行で、最初のコメント文字より後のすべての文字は無視されます。ファイルはUTF-8でエンコードされる必要があります。
特定の具象プロバイダ・クラスが複数の構成ファイル内、または同じ構成ファイル内で繰返し指定されている場合、重複した指定は無視されます。特定のプロバイダを指定した構成ファイルを、プロバイダ自体と同じJARファイル(またはその他の配布単位)内に含める必要はありません。このプロバイダには、構成ファイルの検索時に最初に照会されたクラス・ローダーからアクセスできなければいけません。そのクラス・ローダーは、ファイルが実際にロードされた際のクラス・ローダーと同一であるとは限らないことに注意してください。
プロバイダの検索とインスタンス化は、遅延的に、つまりオン・デマンドで行われます。サービス・ローダーは、以前にロードされたプロバイダのキャッシュを維持管理します。iterator
メソッドを呼出すたびに、イテレータ(キャッシュのすべての要素をインスタンス化順で生成してから、残りすべてのプロバイダを遅延的に検索してインスタンス化し、それぞれを順にキャッシュに追加する)が返されます。キャッシュはreload
メソッドでクリアできます。
サービス・ローダーは常に、呼出し元のセキュリティ・コンテキスト内で実行されます。信頼できるシステム・コードは通常、このクラス内のメソッドやそれらのメソッドから返されるイテレータのメソッドを、特権付きのセキュリティ・コンテキスト内から呼び出すべきです。
このクラスのインスタンスは、複数のスレッドで並行して使用することはできません。
特に指定されていないかぎり、null引数をこのクラスのメソッドに渡すと、NullPointerException
がスローされます。
例あるプロトコル用の一連のエンコーダ/デコーダ・ペアを表現するために設計されたサービス・タイプcom.example.CodecSetがあるとします。この場合、それは次の2つの抽象メソッドを含む抽象クラスです。
各メソッドは適切なオブジェクトを返します。ただし、プロバイダが指定されたエンコーディングをサポートしない場合はnullを返します。通常のプロバイダでは、複数のエンコーディングがサポートされています。public abstract Encoder getEncoder(String encodingName); public abstract Decoder getDecoder(String encodingName);
com.example.impl.StandardCodecsがCodecSetサービスの実装の1つである場合、そのJARファイルには次の名前のファイルも含まれています。
META-INF/services/com.example.CodecSet
このファイルには、次の行が含まれます。
com.example.impl.StandardCodecs # Standard codecs
CodecSetクラスは、初期化時に単一のサービス・インスタンスを作成および保存します。
private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
指定されたエンコーディング名に対応するエンコーダを検索するために、それはstaticファクトリ・メソッドを定義します。このメソッドは、既知で使用可能なプロバイダに対して反復処理を実行し、適切なエンコーダが見つかったかプロバイダの有効期限が切れた場合にのみリターンします。
public static Encoder getEncoder(String encodingName) { for (CodecSet cp : codecSetLoader) { Encoder enc = cp.getEncoder(encodingName); if (enc != null) return enc; } return null; }
getDecoderメソッドも同様に定義されます。
使用上の注意点プロバイダのロードに使用されるクラス・ローダーのクラス・パスにリモート・ネットワークURLが含まれている場合、プロバイダ構成ファイルの検索中にそれらのURLが間接参照されます。
この活動は正常ですが、その場合、Webサーバーのログ内に不可解なエントリが作成される可能性があります。ただし、Webサーバーが正しく構成されていない場合には、この活動によってプロバイダ・ロード・アルゴリズムが擬似的に失敗する可能性があります。
要求されたリソースが存在しない場合、WebサーバーはHTTP 404 (Not Found)応答を返すべきです。ところが、Webサーバーのなかには、そのような場合にHTTP 200 (OK)応答と有用なHTMLエラー・ページを返すように、間違って構成されているものもあります。その場合、このクラスがそのHTMLページをプロバイダ構成ファイルとして解析しようとした時点で、ServiceConfigurationError
がスローされます。この問題の最良の解決策は、間違って構成されたWebサーバーが正しい応答コード(HTTP 404)とHTMLエラー・ページを返すように、修正することです。
修飾子と型 | メソッドと説明 |
---|---|
Iterator<S> |
iterator()
このローダーのサービスの使用可能なプロバイダを、遅延的にロードします。
|
static <S> ServiceLoader<S> |
load(Class<S> service)
指定されたサービス・タイプの新しいサービス・ローダーを、現在のスレッドのコンテキスト・クラス・ローダーを使って作成します。
|
static <S> ServiceLoader<S> |
load(Class<S> service, ClassLoader loader)
指定されたサービス・タイプとクラス・ローダーに対応する新しいサービス・ローダーを作成します。
|
static <S> ServiceLoader<S> |
loadInstalled(Class<S> service)
指定されたサービス・タイプの新しいサービス・ローダーを、拡張クラス・ローダーを使って作成します。
|
void |
reload()
このローダーのプロバイダ・キャッシュをクリアし、すべてのプロバイダが再ロードされるようにします。
|
String |
toString()
このサービスを記述した文字列を返します。
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
forEach, spliterator
public void reload()
このメソッドが呼び出されると、iterator
メソッドの後続の呼出しは、作成されたばかりのローダーが行うのとまったく同様に、プロバイダを一から遅延的に検索およびインスタンス化します。
このメソッドは、実行中のJava仮想マシン内に新しいプロバイダをインストールできるような状況で使用するためのものです。
public Iterator<S> iterator()
このメソッドから返されるイテレータはまず、プロバイダ・キャッシュのすべての要素をインスタンス化された順番で生成します。次に、イテレータは残りすべてのプロバイダを遅延的にロードしてインスタンス化し、各プロバイダを順にキャッシュに追加します。
遅延性を実現するために、使用可能なプロバイダ構成ファイルを解析し、プロバイダをインスタンス化するという実際の作業は、イテレータ自体によって行われます。したがって、そのhasNext
およびnext
メソッドは、プロバイダ構成ファイルが指定された形式に違反している場合、検索およびインスタンス化できないプロバイダ・クラスがプロバイダ構成ファイル内に指定されていた場合、クラスをインスタンス化した結果をサービス・タイプに代入できない場合、または次のプロバイダを検索およびインスタンス化する際にその他のあらゆる種類の例外やエラーがスローされた場合に、ServiceConfigurationError
をスローする可能性があります。サービス・イテレータを使用する場合に、堅牢なコードを記述するために必要なことは、ServiceConfigurationError
をキャッチすることだけです。
そのようなエラーがスローされた場合、イテレータの後続の呼出しは最善の努力を尽くして、次に使用可能なプロバイダを検索およびインスタンス化しようとしますが、一般に、そのような復旧は必ずしも成功するとはかぎりません。
設計上の注意点これらの場合にエラーをスローすることは、極端に見えるかもしれません。このような動作になっている理由は、不正なプロバイダ構成ファイルは不正なクラス・ファイルと同じく、Java仮想マシンの構成方法や使用方法に関する深刻な問題を示していることにあります。このため、復旧しようとしたり、さらに悪いことに何の通知もなく失敗したりするよりも、エラーをスローすることをお薦めします。
このメソッドから返されるイテレータは、削除をサポートしません。そのremove
メソッドを呼び出すと、UnsupportedOperationException
がスローされます。
iterator
、インタフェース: Iterable<S>
Iterator
は、ClassLoader.getResources(String)
メソッドがサービス構成ファイルを見つける順序でリソースを処理します。public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
S
- サービス・タイプのクラスservice
- サービスを表すインタフェースまたは抽象クラスloader
- プロバイダ構成ファイルとプロバイダ・クラスのロードに使用するクラス・ローダー。システム・クラス・ローダー(それが失敗した場合はブートストラップ・クラス・ローダー)を使用する場合はnullpublic static <S> ServiceLoader<S> load(Class<S> service)
このメソッドを次の形式で呼び出すと、上記の動作が行われます。
これは、次のように指定することと同じです。ServiceLoader.load(service)
ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
S
- サービス・タイプのクラスservice
- サービスを表すインタフェースまたは抽象クラスpublic static <S> ServiceLoader<S> loadInstalled(Class<S> service)
この簡易メソッドは単純に、拡張クラス・ローダーを検索し(これをextClassLoaderとする)、次の値を返します
ServiceLoader.load(service, extClassLoader)
拡張クラス・ローダーが見つからない場合はシステム・クラス・ローダーが使用され、システム・クラス・ローダーが存在しない場合はブートストラップ・クラス・ローダーが使用されます。
このメソッドは、インストール済みのプロバイダだけが必要な場合に使用するためのものです。結果として得られるサービスは、現在のJava仮想マシンにインストールされているプロバイダだけを検索およびロードします。アプリケーションのクラス・パス上のプロバイダは無視されます。
S
- サービス・タイプのクラスservice
- サービスを表すインタフェースまたは抽象クラス バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.