12.3. サービスのインポート
概要
このセクションでは、OSGi サービスレジストリーにエクスポートされた OSGi サービスへの参照を取得して使用する方法を説明します。reference
要素または reference-list
要素のいずれかを使用して、OSGi サービスをインポートできます。reference
要素はステートレスサービスへのアクセスに適していますが、reference-list
要素はステートフルサービスへのアクセスに適しています。
サービス参照の管理
OSGi サービス参照を取得するための以下のモデルがサポートされています。
参照マネージャー
参照マネージャーインスタンスは、Blueprint reference
要素によって作成されます。この要素は単一のサービス参照を返すので、ステートレス サービスへのアクセスに推奨のアプローチです。図12.1「ステートレスサービスへの参照」 は、参照マネージャーを使用してステートレスサービスにアクセスするためのモデルの概要を示しています。
図12.1 ステートレスサービスへの参照
クライアント Blueprint コンテナー内の Bean には、OSGi サービスレジストリーからのサービスオブジェクト (バッキングサービス) によってサポートされるプロキシーオブジェクト (提供されたオブジェクト) が注入されます。このモデルは、次のように、ステートレスサービスが交換可能であるという事実を明示的に利用しています。
-
reference
要素の基準と一致する複数のサービスインスタンスが見つかった場合は、参照マネージャーは、バッキングインスタンスのいずれかを任意に選択することができます (交換可能であるため) 。 - バッキングサービスがなくなった場合には、参照マネージャーは、同じタイプの他の利用可能なサービスの 1 つを使用するようにすぐに切り替えることができます。したがって、次のメソッド呼び出しまでの間、プロキシーが同じバッキングサービスに接続されたままであるという保証はありません。
そのため、クライアントとバッキングサービス間のコントラクトは ステートレス であり、クライアントは常に同じサービスインスタンスと通信しているとは限りません。一致するサービスインスタンスがない場合は、ServiceUnavailable
例外を出力する前にプロキシーは一定時間待機します。タイムアウトの長さは、timeout
要素に reference
属性を設定することで設定できます。
参照リストマネージャー
参照リストマネージャーインスタンスは、Blueprint reference-list
要素によって作成されます。この要素はサービス参照のリストを返し、ステートフル サービスへのアクセスに推奨のアプローチです。図12.2「ステートフルサービスへの参照のリスト」 は、参照リストマネージャーを使用してステートフルサービスにアクセスするためのモデルの概要を示しています。
図12.2 ステートフルサービスへの参照のリスト
クライアントの Blueprint コンテナーの Bean は、プロキシーオブジェクトのリストが含まれる java.util.List
オブジェクト (提供済みオブジェクト) で注入されます。各プロキシーは、OSGi サービスレジストリー内の一意のサービスインスタンスによってサポートされています。ステートレスモデルとは異なり、ここではバッキングサービスは互換性があるとは見なされません。実際、リスト内の各プロキシーのライフサイクルは、対応するバッキングサービスのライフサイクルと密接に関連しています。サービスが OSGi レジストリーに登録されると、対応するプロキシーが同時に作成され、プロキシーリストに追加されます。また、サービスが OSGi レジストリーから登録解除されると、対応するプロキシーがプロキシーリストから同時に削除されます。
したがって、プロキシーとそのバッキングサービス間のコントラクトは ステートフル であり、クライアントは、特定のプロキシーでメソッドを呼び出すときに、常に 同じ バッキングサービスと通信していると想定されます。ただし、バッキングサービスが利用できなくなる可能性があり、その場合、プロキシーは古くなります。古いプロキシーでメソッドを呼び出すと、ServiceUnavailable
例外が生成されます。
インターフェイスによるマッチング (ステートレス)
ステートレスサービス参照を取得する最も簡単な方法は、reference
要素の interface
属性を仕様して一致するインターフェイスを指定することです。interface
属性の値がサービスのスーパータイプである場合や、属性値がサービスによって実装された Java インターフェイスである場合、サービスは一致すると見なされます (interface
属性は Java クラスまたは Java インターフェイスのいずれかを指定できます)。
たとえば、ステートレス SavingsAccount
サービスを参照するには、以下のように reference
要素を定義します (例12.1「単一のインターフェイスを使用したサンプルサービスのエクスポート」 を参照)。
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <reference id="savingsRef" interface="org.fusesource.example.SavingsAccount"/> <bean id="client" class="org.fusesource.example.client.Client"> <property name="savingsAccount" ref="savingsRef"/> </bean> </blueprint>
reference
要素によって ID savingsRef
を持つ参照マネージャー Bean が作成されます。参照されたサービスを使用するには、以下に示すように savingsRef
Bean をクライアントクラスのいずれかに注入します。
クライアントクラスにインジェクトされた bean プロパティーは、SavingsAccount
から割り当て可能なあらゆるタイプにすることができます。たとえば、以下のように Client
クラスを定義できます。
package org.fusesource.example.client; import org.fusesource.example.SavingsAccount; public class Client { SavingsAccount savingsAccount; // Bean properties public SavingsAccount getSavingsAccount() { return savingsAccount; } public void setSavingsAccount(SavingsAccount savingsAccount) { this.savingsAccount = savingsAccount; } ... }
インターフェイスによるマッチング (ステートフル)
ステートフルサービス参照を取得する最も簡単な方法は、reference-list
要素の interface
属性を仕様して一致するインターフェイスを指定することです。その後、参照リストマネージャーはすべてのサービスのリストを取得します。interface
属性の値はサービスのスーパータイプか、サービスによって実装されてた Java インターフェイスのいずれかです (interface
属性は Java クラスまたは Java インターフェイスのいずれかを指定できます)。
たとえば、ステートフル SavingsAccount
サービスを参照するには、以下のように reference-list
要素を定義します (例12.1「単一のインターフェイスを使用したサンプルサービスのエクスポート」 を参照)。
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <reference-list id="savingsListRef" interface="org.fusesource.example.SavingsAccount"/> <bean id="client" class="org.fusesource.example.client.Client"> <property name="savingsAccountList" ref="savingsListRef"/> </bean> </blueprint>
reference-list
要素によって ID savingsListRef
を持つ参照リストマネージャー Bean が作成されます。参照されたサービスリストを使用するには、以下に示すように savingsListRef
Bean 参照をクライアントクラスのいずれかに注入します。
デフォルトでは、savingsAccountList
Bean プロパティーはサービスオブジェクトのリストです (たとえば、java.util.List<SavingsAccount>
)。クライアントクラスは次のように定義できます。
package org.fusesource.example.client; import org.fusesource.example.SavingsAccount; public class Client { java.util.List<SavingsAccount> accountList; // Bean properties public java.util.List<SavingsAccount> getSavingsAccountList() { return accountList; } public void setSavingsAccountList( java.util.List<SavingsAccount> accountList ) { this.accountList = accountList; } ... }
インターフェイスとコンポーネント名によるマッチング
ステートレスサービスのインターフェイスとコンポーネント名 (Bean ID) の両方と一致するには、以下のように interface
属性と component-name
属性を reference
要素に指定します。
<reference id="savingsRef" interface="org.fusesource.example.SavingsAccount" component-name="savings"/>
ステートフルサービスのインターフェイスとコンポーネント名 (Bean ID) の両方と一致するには、以下のように interface
属性と component-name
属性を reference-list
要素に指定します。
<reference-list id="savingsRef" interface="org.fusesource.example.SavingsAccount" component-name="savings"/>
フィルターを使用したサービスプロパティーの照合
フィルターに対してサービスプロパティーを照合して、サービスを選択できます。フィルターは、reference
要素または reference-list
要素で filter
属性を使用して指定されます。filter
属性の値は LDAP フィルター式である必要があります。たとえば、bank.name
サービスプロパティーが HighStreetBank
の場合にマッチするフィルターを定義するには、以下の LDAP フィルター式を使用します。
(bank.name=HighStreetBank)
2 つのサービスプロパティーの値を一致させるには、論理 and
で式を組み合わせる &
結合を使用できます。たとえば、foo
プロパティーが FooValue
と等しく、bar
プロパティーが BarValue
と等しいことを必要とするには、以下の LDAP フィルター式を使用できます。
(&(foo=FooValue)(bar=BarValue))
LDAP フィルター式の完全な構文は、OSGi コア仕様 のセクション 3.2.7 を参照してください。
フィルターは、interface
および component-name
設定と組み合わせることもできます。この設定では、指定したすべての条件が一致する必要があります。
たとえば、SavingsAccount
タイプのステートレス サービスを HighStreetBank
と等しい bank.name
サービスプロパティーと一致させるには、以下のように reference
要素を定義します。
<reference id="savingsRef" interface="org.fusesource.example.SavingsAccount" filter="(bank.name=HighStreetBank)"/>
SavingsAccount
タイプのステートフル サービスを HighStreetBank
と等しい bank.name
サービスプロパティーと一致させるには、以下のように reference-list
要素を定義します。
<reference-list id="savingsRef" interface="org.fusesource.example.SavingsAccount" filter="(bank.name=HighStreetBank)"/>
必須/任意の指定
デフォルトでは、OSGi サービスへの参照は必須であると見なされます (必須の依存関係 参照)。要素に availability
属性を設定して、reference
要素または reference-list
要素の依存関係動作をカスタマイズできます。
availability
属性には、可能な値が 2 つあります。
-
mandatory
(デフォルト) は、通常の Blueprint コンテナーの初期化中に依存関係を解決する必要があることを意味します。 -
optional
は、依存関係が初期化中に解決される必要がないことを意味します。
以下の reference
要素の例では、参照が必須の依存関係であることを明示的に宣言する方法を示しています。
<reference id="savingsRef" interface="org.fusesource.example.SavingsAccount" availability="mandatory"/>
参照リスナーの指定
たとえば、一部のサービス参照に optional
が使用できることを宣言した場合など、OSGi 環境の動的な性質に対応するには、バッキングサービスがレジストリーにバインドされたときと、レジストリーからバインド解除されたときを追跡すると便利なことがよくあります。サービスバインディングおよびバインドイベントの通知を受信するには、reference-listener
要素を reference
要素または reference-list
要素の子として定義できます。
たとえば、以下の Blueprint 設定は、参照リスナーを、ID savingsRef
を持つ参照マネージャーの子として定義する方法を示しています。
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <reference id="savingsRef" interface="org.fusesource.example.SavingsAccount" > <reference-listener bind-method="onBind" unbind-method="onUnbind"> <bean class="org.fusesource.example.client.Listener"/> </reference-listener> </reference> <bean id="client" class="org.fusesource.example.client.Client"> <property name="savingsAcc" ref="savingsRef"/> </bean> </blueprint>
前述の設定は、bind
と unbind
イベントをリッスンし、そのコールバックとして org.fusesource.example.client.Listener
タイプのインスタンスを登録します。イベントは、savingsRef
参照マネージャーのバッキングサービスがバインドまたはバインド解除されるたびに生成されます。
以下の例は、Listener
クラスの実装例を示しています。
package org.fusesource.example.client; import org.osgi.framework.ServiceReference; public class Listener { public void onBind(ServiceReference ref) { System.out.println("Bound service: " + ref); } public void onUnbind(ServiceReference ref) { System.out.println("Unbound service: " + ref); } }
メソッド名 onBind
および onUnbind
は、それぞれ bind-method
属性および unbind-method
属性によって指定されます。これらのコールバックメソッドは両方とも org.osgi.framework.ServiceReference
引数を取ります。