JavaTM Platform
Standard Ed. 6

java.util
クラス ServiceLoader<S>

java.lang.Object
  上位を拡張 java.util.ServiceLoader<S>
型パラメータ:
S - このローダーによってロードされるサービスの型
すべての実装されたインタフェース:
Iterable<S>

public final class ServiceLoader<S>
extends Object
implements Iterable<S>

簡単なサービスプロバイダロード機構です。

「サービス」とは、既知のインタフェースおよびクラス (通常は抽象クラス) のセットです。「サービスプロバイダ」とは、特定のサービスの実装です。通常、プロバイダのクラスによって、サービス自体に定義されているクラスのインタフェースとサブクラスが実装されます。サービスプロバイダを Java プラットフォームの実装にインストールするときは、拡張機能の形式、つまり、拡張機能の通常のディレクトリに配置される jar ファイルの形式で行われます。プロバイダを利用可能にするには、アプリケーションのクラスパスに追加するか、プラットフォーム固有の方法を使います。

サービスはロード目的のために、単一の型、つまり単一のインタフェースまたは抽象クラスとして表現されます。(具象クラスも使用できますが、それはお勧めできません。)特定のサービスのプロバイダには、その「サービスタイプ」をプロバイダに固有のデータやコードで拡張した、1 つ以上の具象クラスが含まれています。通常、「プロバイダクラス」には、プロバイダ自体がすべて含まれることはありません。要求時に実際のプロバイダを作成できるコードとともに、プロバイダが特定の要求を満たすことができるかどうかを識別するために必要な情報で構成されるプロキシになっています。プロバイダクラスの内容は、個別のサービスに大きく依存します。1 つのクラスまたはインタフェースでプロバイダクラスを統合することはできません。このため、このような型はここでは定義されていません。この機能が強制する唯一の要求は、プロバイダクラスには、ロード中にインスタンスを生成できるように、引数を取らないコンストラクタが存在しなければいけない、ということです。

サービスプロバイダは、リソースディレクトリ META-INF/services に「プロバイダ構成ファイル」を配置することによって識別されます。このファイルの名前は、サービスの型の完全修飾バイナリ名になります。このファイルには、具象プロバイダクラスの完全修飾バイナリ名が 1 行に 1 つずつ記述されます。それぞれの名前を囲む空白文字とタブ文字、および空白行は無視されます。コメント文字は '#' ('\u0023'NUMBER SIGN) です。 行頭にコメント文字が挿入されている場合、その行のすべての文字は無視されます。ファイルは UTF-8 で符号化されている必要があります。

特定の具象プロバイダクラスが複数の構成ファイル内、または同じ構成ファイル内で繰り返し指定されている場合、重複した指定は無視されます。特定のプロバイダを指定した構成ファイルを、プロバイダ自体と同じ JAR ファイル (またはその他の配布単位) 内に含める必要はありません。このプロバイダには、構成ファイルの検索時に最初に照会されたクラスローダーからアクセスできなければなりません。そのクラスローダーは、ファイルが実際にロードされた際のクラスローダーと同一であるとは限らないことに注意してください。

プロバイダの検索とインスタンス化は、遅延的に、つまりオンデマンドで行われます。サービスローダーは、以前にロードされたプロバイダのキャッシュを維持管理します。iterator メソッドが呼び出されるたびに、反復子が 1 つ返されます。この反復子はまず、キャッシュのすべての要素をインスタンス化された順番で生成し、次に、残りすべてのプロバイダを遅延的に検索してインスタンス化し、各プロバイダを順にキャッシュに追加します。reload メソッドを使えば、キャッシュをクリアーできます。

サービスローダーは常に、呼び出し元のセキュリティーコンテキスト内で実行されます。信頼できるシステムコードは通常、このクラス内のメソッドやそれらのメソッドから返される反復子のメソッドを、特権付きのセキュリティーコンテキスト内から呼び出すべきです。

このクラスのインスタンスは、複数のスレッドで並行して使用することはできません。

特に指定されていないかぎり、このクラス内のメソッドに null 引数を渡すと、NullPointerException がスローされます。

あるプロトコル用の一連のエンコーダ/デコーダペアを表現するために設計されたサービスタイプ com.example.CodecSet があるとします。この場合、それは次の 2 つの抽象メソッドを含む抽象クラスです。

 public abstract Encoder getEncoder(String encodingName);
 public abstract Decoder getDecoder(String encodingName);
各メソッドは適切なオブジェクトを返します。ただし、プロバイダが指定されたエンコーディングをサポートしない場合は null を返します。通常のプロバイダでは、複数のエンコーディングがサポートされています。

com.example.impl.StandardCodecsCodecSet サービスの実装の 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 エラーページを返すように、修正することです。

導入されたバージョン:
1.6

メソッドの概要
 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()
          このサービスを記述した文字列を返します。
 
クラス java.lang.Object から継承されたメソッド
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

メソッドの詳細

reload

public void reload()
このローダーのプロバイダキャッシュをクリアーし、すべてのプロバイダが再ロードされるようにします。

このメソッドが呼び出されると、iterator メソッドの後続の呼び出しは、作成されたばかりのローダーが行うのとまったく同様に、プロバイダを一から遅延的に検索およびインスタンス化します。

このメソッドは、実行中の Java 仮想マシン内に新しいプロバイダをインストールできるような状況で使用するためのものです。


iterator

public Iterator<S> iterator()
このローダーのサービスの使用可能なプロバイダを、遅延的にロードします。

このメソッドから返される反復子はまず、プロバイダキャッシュのすべての要素をインスタンス化された順番で生成します。次に、反復子は残りすべてのプロバイダを遅延的にロードしてインスタンス化し、各プロバイダを順にキャッシュに追加します。

遅延性を実現するために、使用可能なプロバイダ構成ファイルを解析し、プロバイダをインスタンス化するという実際の作業は、反復子自体によって行われます。したがって、その hasNext および next メソッドは、プロバイダ構成ファイルが指定された形式に違反している場合、検索およびインスタンス化できないプロバイダクラスがプロバイダ構成ファイル内に指定されていた場合、クラスをインスタンス化した結果をサービスタイプに代入できない場合、または次のプロバイダを検索およびインスタンス化する際にその他のあらゆる種類の例外やエラーがスローされた場合に、ServiceConfigurationError をスローする可能性があります。サービス反復子を使用する場合に、頑強なコードを記述するために必要なことは、ServiceConfigurationError をキャッチすることだけです。

そのようなエラーがスローされた場合、反復子の後続の呼び出しは最善の努力を尽くして、次に使用可能なプロバイダを検索およびインスタンス化しようとしますが、一般に、そのような復旧は必ずしも成功するとはかぎりません。

設計上の注意点 これらの場合にエラーをスローすることは、極端に見えるかもしれません。このような動作になっている理由は、不正なプロバイダ構成ファイルは不正なクラスファイルと同じく、Java 仮想マシンの構成方法や使用方法に関する深刻な問題を示していることにあります。このため、復旧しようとしたり、さらに悪いことに何の通知もなく失敗したりするよりも、エラーをスローすることをお勧めします。

このメソッドから返される反復子は、削除をサポートしません。その remove メソッドを呼び出すと、UnsupportedOperationException がスローされます。

定義:
インタフェース Iterable<S> 内の iterator
戻り値:
このローダーのサービスのプロバイダを遅延的にロードする反復子

load

public static <S> ServiceLoader<S> load(Class<S> service,
                                        ClassLoader loader)
指定されたサービスタイプとクラスローダーに対応する新しいサービスローダーを作成します。

パラメータ:
service - サービスを表すインタフェースまたは抽象クラス
loader - プロバイダ構成ファイルとプロバイダクラスのロードに使用するクラスローダー。システムクラスローダー (それが失敗した場合はブートストラップクラスローダー) を使用する場合は null
戻り値:
新しいサービスローダー

load

public static <S> ServiceLoader<S> load(Class<S> service)
指定されたサービスタイプの新しいサービスローダーを、現在のスレッドの コンテキストクラスローダー を使って作成します。

このメソッドを次の形式で呼び出すと、上記の動作が行われます。

 ServiceLoader.load(service)
これは、次のように指定することと同じです。
 ServiceLoader.load(service,
                    Thread.currentThread().getContextClassLoader())

パラメータ:
service - サービスを表すインタフェースまたは抽象クラス
戻り値:
新しいサービスローダー

loadInstalled

public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
指定されたサービスタイプの新しいサービスローダーを、拡張クラスローダーを使って作成します。

この簡易メソッドは単純に、拡張クラスローダーを検索し (これを extClassLoader とする)、次の値を返します。

 ServiceLoader.load(service, extClassLoader)

拡張クラスローダーが見つからない場合はシステムクラスローダーが使用され、システムクラスローダーが存在しない場合はブートストラップクラスローダーが使用されます。

このメソッドは、インストール済みのプロバイダだけが必要な場合に使用するためのものです。結果として得られるサービスは、現在の Java 仮想マシンにインストールされているプロバイダだけを検索およびロードします。アプリケーションのクラスパス上のプロバイダは無視されます。

パラメータ:
service - サービスを表すインタフェースまたは抽象クラス
戻り値:
新しいサービスローダー

toString

public String toString()
このサービスを記述した文字列を返します。

オーバーライド:
クラス Object 内の toString
戻り値:
説明文字列

JavaTM Platform
Standard Ed. 6

バグの報告と機能のリクエスト
さらに詳しい API リファレンスおよび開発者ドキュメントについては、Java SE 開発者用ドキュメントを参照してください。開発者向けの詳細な解説、概念の概要、用語の定義、バグの回避策、およびコード実例が含まれています。

Copyright 2006 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Documentation Redistribution Policy も参照してください。