Oracle® Fusion Middleware Oracle WebLogic Server 12.1.3アプリケーションの開発 12c (12.1.3) E57574-04 |
|
前 |
次 |
WebLogic Server 12.1.3は、Contexts and Dependency Injection (CDI)仕様の実装を提供します。CDI仕様には、注入を使用してアプリケーション内の依存関係を指定するための一連のサービスが定義されています。CDIは、Beanのコンテキストに基づいたライフ・サイクル管理、型保証注入ポイント、疎結合イベント・フレームワーク、疎結合インターセプタおよびデコレータ、Beanのかわりの実装、Unified Expression Language (EL)によるBeanのナビゲーション、CDI拡張がサード・パーティのフレームワークまたは将来のJava EEコンポーネントをサポートできるようにするサービス・プロバイダ・インタフェース(SPI)を提供します。
次の項では、アプリケーション内でのCDI for the Java EE platformの使用方法について説明します。
CDIは、『Java Specification Request (JSR) 299: Contexts and Dependency Injection for the Java EE platform』によって指定されています。この仕様は、以前はWeb Beansと呼ばれていました。CDIは、次の関連する仕様を使用します。
Java EE 6のマネージドBeanの仕様。これは、『JSR 316: Java Platform, Enterprise Edition 6 (Java EE 6) Specification』の一部です。
インターセプタの仕様。これは、『JSR 318: Enterprise JavaBeans specification』の一部です。
CDIは、次の機能を提供します。
コンテキスト。この機能により、ステートフル・コンポーネントのライフ・サイクルおよび相互作用を、明確に定義されているが拡張可能なライフ・サイクル・コンテキストにバインドできるようになります。
依存関係インジェクション。この機能により、型保証された方法でコンポーネントをアプリケーションに注入でき、デプロイメント時に特定のインタフェースのどの実装を注入するのかを選択できます。
CDIは、次のようなJava EEの主なコンポーネント・テクノロジと統合されます。
サーブレット
JavaServer Pages (JSP)
JavaServer Faces (JSF)
Enterprise JavaBeans (EJB)
Java EE Connector Architecture (JCA)
Webサービス
このような統合により、サーブレットやEJBコンポーネントなど標準Java EEオブジェクトが、依存関係のCDI注入を使用できるようになります。CDI注入により、たとえば、WebアプリケーションでJSFテクノロジとともにマネージドBeanを簡単に使用できるようになります。
詳細は、Java EE 6チュートリアルのContexts and Dependency Injection for the Java EE Platformの概要に関する項を参照してください。
CDIの使用方法を示す完全な例は、EXAMPLES_HOME
\wl_server\examples\src\examples\javaee6\cdi
にインストールされたcdi
サンプル・アプリケーションで提供されています。EXAMPLES_HOME
はWebLogic Serverのコード・サンプルを構成するディレクトリです。WebLogic Serverのコード・サンプルの詳細は、『Oracle WebLogic Serverの理解』のサンプル・アプリケーションおよびサンプル・コードに関する項を参照してください。
Beanは、CDIによって作成および管理できるオブジェクトのソースです。詳細は、Java EE 6チュートリアルのBeanに関する項を参照してください。
マネージドBeanは、CDIアプリケーションの基本コンポーネントであり、CDIによって作成および管理できるBeanを定義します。マネージドBeanを定義するには、次の条件のいずれかを満たす最上位レベルのプレーンな従来型Javaオブジェクト(POJO)クラスを定義します。
このクラスは、他のJava EE仕様によってマネージドBeanとなるように定義されています。
このクラスは、Java EE 6チュートリアルのマネージドBeansに関する項にリストされているJSR 299で必要とされる条件をすべて満たします。
注意: マネージドBeanを定義するために、アノテーションなど特別な宣言は必要ありません。アプリケーションのマネージドBeanを注入に使用できるようにするには、「CDIアプリケーションの構成」の説明に従ってアプリケーションを構成する必要があります。 |
自身で定義するBeanを使用するには、それらを、JavaServer Facesアプリケーションなどのアプリケーションが使用できる別のBeanに注入します。詳細は、Java EE 6チュートリアルのBeanの注入に関する項を参照してください。
CDIでは、Bean名ではなく、注入ポイントで指定されているJavaの型に基づいてBeanクラスを選択することで、型を保証してBeanを注入できます。CDIでは、注入ポイントのJavaの型からBeanを注入する場所も判別されます。
この点において、CDIのBeanの注入は、Java EE 5のリソース注入とは異なります。Java EE 5のリソース注入では、リソースの文字列名から注入するリソースが選択されます。たとえば、javax.annotation.Resource
アノテーションで注入されるデータ・ソースは、その文字列名によって識別されます。
Beanを注入するには、注入するBeanを使用するクラス内に注入ポイントを作成することで、Beanのインスタンスを取得します。javax.inject.Inject
アノテーションで、次のプログラム要素の1つに注釈付けすることで注入ポイントを作成します。
インスタンス・クラス・フィールド
イニシャライザ・メソッド・パラメータ
Beanコンストラクタ・パラメータ
例9-1は、@Inject
アノテーションを使用してBeanを別のBeanに注入する方法を示します。
Beanのスコープは、そのBeanを使用するアプリケーションとユーザーの対話の期間を定義します。Webアプリケーションが、別のBeanクラスを注入するBeanを使用できるようにするには、そのBeanがアプリケーションとユーザーの対話の期間にわたって状態を保持できるようにする必要があります。
Beanのスコープを定義するには、Beanのクラス宣言にそのスコープのアノテーションを付けます。javax.enterprise.context
パッケージは、次のスコープを宣言します。
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
@Dependent
これらのスコープの詳細は、Java EE 6チュートリアルのスコープの使用方法に関する項を参照してください。
Beanのスコープを定義しない場合、Beanのスコープはデフォルトの@Dependent
になります。@Dependent
のスコープは、そのBeanのライフ・サイクルを、そのBeanの注入先のオブジェクトのライフ・サイクルにすることを指定します。
@Dependent以外の
事前定義済スコープは、コンテキスト・スコープです。CDIは、コンテキスト・スコープのBeanを、Java EE仕様によって定義されるライフ・サイクルを持つコンテキストに配置します。たとえば、セッション・コンテキストとそのBeanは、HTTPセッションのライフタイムの間のみ存在します。注入されるBeanへの参照は、コンテキストを認識しています。参照は常に、参照するスレッドのコンテキストに関連付けられたBeanに適用されます。CDIコンテナによって、オブジェクトは、それらのオブジェクトに対して指定されているスコープによって決定される適切な時点で作成され、注入されます。
例9-2は、Beanのスコープを定義する方法を示します。
例9-2 Beanのスコープの定義
この例では、Accountant
Beanクラスのスコープを@RequestScoped
と定義します。
この例のAccountant
クラスは、@BeanCounter
修飾子によって修飾されています。詳細は、「修飾子の使用方法」を参照してください。
package com.example.managers; import javax.enterprise.context.RequestScoped; @RequestScoped @BeanCounter public class Accountant implements Manager { ... }
注入ポイントでのBeanのスコープのオーバーライドにより、アプリケーションは、デフォルト・スコープ@Dependent
を持つBeanの新しいインスタンスをリクエストできます。@Dependent
のスコープは、そのBeanのライフ・サイクルを、そのBeanの注入先のオブジェクトのライフ・サイクルにすることを指定します。CDIコンテナは、インスタンスにその他のライフ・サイクル管理を提供しません。スコープの詳細は、「Beanのスコープの定義」を参照してください。
注意: Beanのスコープのオーバーライドによる影響は、特にオーバーライドされるスコープが@Request や@Session の場合に、予期できない望ましくないものになることがあります。 |
注入ポイントでBeanのスコープをオーバーライドするには、@Injectアノテーションのかわりに
javax.enterprise.inject.Newアノテーションを使用することでBeanを注入します。
@Inject
アノテーションの詳細は、「Beanの注入」を参照してください。
修飾子によって、特定のBeanタイプの実装を複数提供できます。修飾子を使用する場合、開発時に複数の実装の中から選択します。詳細は、Java EE 6チュートリアルの修飾子の使用方法に関する項を参照してください。
修飾子の使用方法には、次の項で説明するタスクが含まれます。
修飾子は、アプリケーションによって定義されるアノテーションであり、Beanタイプの実装の識別を可能にします。提供するBeanタイプの実装ごとに修飾子を1つ定義します。
修飾子は、Beanタイプの複数の実装を提供し、かつ代替を使用していない場合にのみ定義します。Beanタイプに対して修飾子が定義されていない場合、そのタイプのBeanが注入されるときにCDIによって事前定義済修飾子@Default
が適用されます。
注意: CDIでは、修飾子が特定のBeanに一意である必要はありません。1つの修飾子を複数のBeanタイプに定義できます。 |
修飾子を定義する手順は、次のとおりです。
その修飾子を表すJavaアノテーション・タイプを定義します。
javax.inject.Qualifier
アノテーションでアノテーション・タイプの宣言に注釈付けします。
実行時に仮想マシンによってその修飾子が保持されることを指定します。
このためには、java.lang.annotation.Retention(RUNTIME)
メタアノテーションを使用します。
その修飾子をプログラム要素METHOD
、FIELD
、PARAMETER
およびTYPE
に適用できることを指定します。
このためには、java.lang.annotation.Target({METHOD, FIELD, PARAMETER, TYPE})
メタアノテーションを使用します。
次の例では、修飾子@BeanCounter
および@PeopleManager
を、同じBeanタイプの別々の実装に対して定義する方法を示します。
例9-3 @BeanCounter修飾子の定義
この例では、@BeanCounter
修飾子を定義します。
package com.example.managers; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface BeanCounter {}
例9-4 @PeopleManager修飾子の定義
この例では、@PeopleManager
修飾子を定義します。
package com.example.managers; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface PeopleManager {}
Beanに修飾子を適用すると、Beanタイプの実装が特定されます。1つのBeanに、任意の数の修飾子を適用することも、修飾子を適用しないこともできます。Beanに修飾子が適用されていない場合、CDIによって暗黙的に事前定義済修飾子@Default
がそのBeanに適用されます。
注意: CDIでは、修飾子が特定のBeanに一意である必要はありません。1つのアプリケーション内で使用可能な一連のBeanで異なるタイプのBeanに同じ修飾子を適用できます。 |
修飾子をBeanに適用するには、そのBeanのクラス宣言に、適用する各修飾子で注釈付けします。Beanに適用する修飾子は、「Beanタイプの実装に対する修飾子の定義」の説明に従って定義する必要があります。
次の例では、修飾子@BeanCounter
および@PeopleManager
をManager
Beanタイプの別々の実装に対して適用する方法を示します。
例9-5 Beanへの@BeanCounter修飾子の適用
この例では、@BeanCounter
修飾子をAccountant
クラスに適用します。Accountant
クラスは、Manager
Beanタイプの実装です。@BeanCounter
修飾子は、例9-3で定義されています。
package com.example.managers; ... @BeanCounter public class Accountant implements Manager {...}
例9-6 Beanへの@PeopleManager修飾子の適用
この例では、@PeopleManager
修飾子をBoss
クラスに適用します。Boss
クラスは、Manager
Beanタイプの実装です。@PeopleManager
修飾子は、例9-4で定義されています。
package com.example.managers; ... @PeopleManager public class Boss implements Manager {...}
修飾Beanを注入するには、注入ポイントを作成し、その注入ポイントにBeanの修飾子で注釈付けします。注入ポイントの修飾子は、注入ターゲットの全体的な要件を定義します。CDIアプリケーションには、注入ポイントのタイプと、注入ポイントに注釈付けされている修飾子に一致するCDIマネージドBeanが含まれている必要があります。それ以外の場合は、デプロイメント・エラーが発生します。注入ポイントの作成方法の詳細は、「Beanの注入」を参照してください。
注入ポイントに注釈付けしない場合、デフォルトで事前定義済修飾子@Default
がその注入ポイントに適用されます。
CDIでは、注入ポイントは、最初にBeanタイプを一致させ、次にそのタイプの実装を注入ポイントの修飾子と一致させることで解決されます。
アクティブなBeanクラスのうちの1つのみを、注入ポイントのBeanタイプおよび修飾子と一致させることができます。それ以外の場合は、エラーが発生します。
Beanクラスは、次の状況のいずれかでアクティブです。
Beanクラスが、有効化されている代替です。
Beanクラスが、代替でなく、そのBeanタイプに対して有効化されている代替がありません。
代替の詳細は、「Beanタイプの代替の実装の提供」を参照してください。
例9-7は、修飾Beanの注入方法を示します。
例9-7 修飾Beanの注入
この例では、Manager
Beanタイプの@BeanCounter
実装を注入します。Manager
Beanタイプは、次のクラスによって実装されています。
この例では、Accountant
クラスが注入されます。それは、このクラスのBeanタイプと修飾子が、注入ポイントのBeanタイプと修飾子に一致するためです。
package com.example.managers; ... import javax.inject.Inject; ... public class PennyPincher { @Inject @BeanCounter Manager accountant; ... }
エンタープライズ・アプリケーションの開発、テスト、および本番デプロイメントの各環境は、大きく異なる場合があります。構成、リソースの可用性、およびパフォーマンスの要件の相違により、1つの環境に適したBeanクラスが、別の環境には合わないことがあります。
同じアプリケーションでも、デプロイメント・シナリオの相違によって、異なるビジネス・ロジックが必要とされる場合もあります。たとえば、注文処理アプリケーションでは、国固有の消費税法によって国固有の消費税のビジネス・ロジックが必要な場合もあります。
Beanタイプの代替の実装を提供することにより、そのような異なる要件を満たすためにデプロイメント時にアプリケーションを変更できます。CDIでは、対応するプライマリの実装のかわりに、任意の数の代替のBeanタイプの実装から注入するものを選択できます。詳細は、Java EE 6チュートリアルの代替の使用方法に関する項を参照してください。
Beanタイプの代替の実装の提供には、次の項で説明するタスクが含まれます。
Beanタイプの代替の実装を定義する手順は、次のとおりです。
Beanタイプのプライマリの実装と同じBeanタイプのBeanクラスを作成します。
どの代替もアプリケーションに注入できるようにするには、すべての代替とプライマリの実装が、すべて同じBeanタイプであることが必要です。Beanの注入方法の詳細は、「Beanの注入」を参照してください。
avax.enterprise.inject.Alternative
アノテーションで実装のクラス宣言に注釈付けします。
注意: デフォルトで必ずプライマリの実装が選択されるようにするには、プライマリの実装のクラス宣言に@Alternative で注釈付けしないでください。 |
次の例では、1つのBeanタイプのプライマリの実装と代替の実装の宣言を示します。代替の実装は、テストで使用するための模擬の実装です。
例9-8 Beanタイプのプライマリの実装の宣言
この例では、BeanタイプOrder
のプライマリの実装OrderImpl
を宣言します。
package com.example.orderprocessor; ... public class OrderImpl implements Order { ... }
例9-9 Beanタイプの代替の実装の宣言
この例では、BeanタイプOrder
の代替の実装MockOrderImpl
を宣言します。このBeanタイプのプライマリの実装の宣言を例9-8に示します。
package com.example.orderprocessor; ... import javax.enterprise.inject.Alternative; @Alternative public class MockOrderImpl implements Order { ... }
デフォルトでは、CDIはアプリケーションへの注入にBeanタイプのプライマリの実装を選択します。代替の実装を注入する必要がある場合は、明示的にその代替を選択する必要があります。
アプリケーションに対して代替の実装を選択する手順は、次のとおりです。
beans.xml
ファイルのalternatives
要素に、代替のclass
要素を追加します。
class
要素に、代替の完全修飾クラス名を指定します。
beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください。
例9-16は、Beanタイプの代替の実装を選択するためのbeans.xml
ファイルのclass
要素を示しています。
CDIでは、スコープおよび修飾子をセッションBeanに適用できます。セッションBeanは、次の要件のいずれかを満たすEJBコンポーネントです。
Beanを実装するクラスには、次のいずれかのアノテーションが付いています。
javax.ejb.Singleton
。シングルトン・セッションBeanを指定します。
javax.ejb.Stateful
。ステートフル・セッションBeanを指定します。
javax.ejb.Stateless
。ステートレス・セッションBeanを指定します。
そのBeanが、ejb-jar.xml
デプロイメント記述子ファイルにリストされています。
セッションBeanの詳細は、次のドキュメントを参照してください。
Oracle WebLogic Server Enterprise JavaBeansの開発
Oracle WebLogic Server Enterprise JavaBeansバージョン2.1の開発
CDIによりセッションBeanに適用できるスコープは、表9-1に示すようにセッションBeanのタイプに応じて異なります。
表9-1 セッションBeanに適用できるCDIスコープ
セッションBeanタイプ | 適用できるスコープ |
---|---|
シングルトン |
次のスコープのいずれかです。
|
ステートフル |
任意 |
ステートレス |
Dependent |
CDIにおけるスコープの詳細は、「Beanのスコープの定義」を参照してください。
CDIで、ステートフル・セッションBeanへの参照が注入されるときは、CDIによってBeanが作成され、Beanのフィールドが注入され、そのスコープに応じてステートフル・セッションBeanが管理されます。コンテキストを破棄するときは、CDIによってステートフル・セッションBeanの削除メソッドがコールされ、そのBeanが削除されます。
CDIでは、任意の修飾子をセッションBeanに適用できます。CDIでは、セッションBeanに適用できる修飾子のタイプに制限はありません。CDIにおける修飾子の詳細は、「修飾子の使用方法」を参照してください。
プロデューサ・メソッドは、注入可能なオブジェクトを生成するメソッドです。
ディスポーザ・メソッドは、アプリケーションが、プロデューサ・メソッドから返されたオブジェクトに、カスタマイズされたクリーンアップを実行できるようにします。
プロデューサ・フィールドは、オブジェクトを生成するBeanのフィールドです。プロデューサ・フィールドは、プロデューサ・メソッドの単純な代替です。
詳細は、Java EE 6チュートリアルのプロデューサ・メソッドおよびフィールドの使用方法に関する項を参照してください。
プロデューサ・メソッドにより、アプリケーションはCDIマネージドBeanの作成方法をカスタマイズできます。このカスタマイズには、CDIがBeanを解決するために通常使用するプロセスのオーバーライドも含まれます。プロデューサ・メソッドにより、CDI Beanクラスのインスタンスではないオブジェクトを注入できるようになります。
プロデューサ・メソッドは、CDI BeanクラスまたはセッションBeanクラスのメソッドであることが必要です。ただし、プロデューサ・メソッドは、CDI Beanクラスのインスタンスではないオブジェクトを返すことができます。この状況では、プロデューサ・メソッドはBeanタイプが一致するオブジェクトを返す必要があります。
プロデューサ・メソッドには、任意の数のパラメータを指定できます。必要に応じて、これらのパラメータに修飾子を適用できます。プロデューサ・メソッドのすべてのパラメータは、注入ポイントです。したがって、プロデューサ・メソッドのパラメータには、@Inject
アノテーションは必要ありません。
プロデューサ・メソッドを定義するには、javax.enterprise.inject.Produces
アノテーションでメソッドの宣言に注釈付けします。
プロデューサ・メソッドがnullを返すことがある場合は、メソッドのスコープをDependentに設定します。
注意: アプリケーション・コードでプロデューサ・メソッドを直接コールしてもCDIは起動されません。 |
プロデューサ・メソッドの定義の例は、例9-11を参照してください。
プロデューサ・メソッドから返されるオブジェクトのカスタマイズ・クリーンアップが必要な場合は、プロデューサ・メソッドを宣言するクラスでディスポーザ・メソッドを定義します。
ディスポーザ・メソッドを定義するには、javax.enterprise.inject.Disposes
アノテーションで、メソッドの宣言の破棄されるパラメータに注釈付けします。破棄されるパラメータのタイプは、プロデューサ・メソッドの戻りタイプと同じであることが必要です。
ディスポーザ・メソッドは、破棄されるオブジェクトの注入ポイントが、プロデューサ・メソッドのタイプと修飾子の両方に一致する場合に、プロデューサ・メソッドと一致します。1つのディスポーザ・メソッドをクラス内の複数のプロデューサ・メソッドに一致するように定義できます。
例9-11は、@Produces
アノテーションを使用してプロデューサ・メソッドを定義する方法と、@Disposes
アノテーションを使用してディスポーザ・メソッドを定義する方法を示しています。
例9-11 プロデューサ・メソッドとディスポーザ・メソッドの定義
この例では、プロデューサ・メソッドconnect
とディスポーザ・メソッドclose
を定義します。
プロデューサ・メソッドconnect
は、タイプConnection
のオブジェクトを返します。ディスポーザ・メソッドclose
では、パラメータconnection
が、破棄されるパラメータです。このパラメータのタイプは、プロデューサ・メソッドの戻りタイプに一致するタイプConnection
です。
実行時に、CDIフレームワークによってSomeClass
のインスタンスが作成され、プロデューサ・メソッドがコールされます。したがって、CDIフレームワークが、プロデューサ・メソッドに渡されるパラメータの注入を担当します。
プロデューサ・メソッドのスコープは@RequestScoped
です。リクエスト・コンテキストが破棄されるときに、Connection
オブジェクトがそのリクエスト・コンテキストにある場合、CDIによってこのオブジェクトに対してディスポーザ・メソッドがコールされます。そのディスポーザ・メソッドへのコールでは、CDIによってConnection
オブジェクトがパラメータとして渡されます。
import javax.enterprise.inject.Produces; import javax.enterprise.inject.Disposes; import javax.enterprise.context.RequestScoped; public class SomeClass { @Produces @RequestScoped public Connection connect(User user) { return createConnection(user.getId(), user.getPassword()); } private Connection createConnection( String id, String password) {...} public void close(@Disposes Connection connection) { connection.close(); } }
プロデューサ・フィールドは、プロデューサ・メソッドの単純な代替です。プロデューサ・フィールドは、マネージドBeanクラスまたはセッションBeanクラスのフィールドにする必要があります。プロデューサ・フィールドは、次の制約に従って、静的である場合も静的でない場合もあります。
セッションBeanクラスでは、プロデューサ・フィールドは静的フィールドであることが必要です。
マネージドBeanクラスでは、プロデューサ・フィールドは、静的でも静的でなくても構いません。
プロデューサ・フィールドを定義するには、javax.enterprise.inject.Produces
アノテーションでフィールドの宣言に注釈付けします。
プロデューサ・フィールドにアクセスしたときにnullが含まれている可能性がある場合は、フィールドのスコープをDependentに設定します。
注意: アプリケーション・コード内でプロデューサ・フィールドを直接使用すると、CDIは起動しません。 |
プロデューサ・フィールドには、ディスポーザはありません。
CDIマネージドBeanクラスおよびそれらのスーパークラスでは、マネージドBeanの初期化と破棄の準備のためのアノテーションがサポートされています。これらのアノテーションは、『JSR 250: Common Annotations for the Java Platform』で定義されています。詳細は、第8章「Java EEアノテーションと依存関係インジェクションの使用」を参照してください。
マネージドBeanの初期化では、依存関係インジェクションの後、クラスがサービスを開始する前にCDIフレームワークがコールする必要があるライフ・サイクル・コールバック・メソッドを指定します。
マネージドBeanを初期化する手順は、次のとおりです。
マネージドBeanクラスまたはそのスーパークラスのいずれかで、必要な初期化を実行するメソッドを定義します。
javax.annotation.PostConstruct
アノテーションで、メソッドの宣言に注釈付けします。
マネージドBeanがコンポーネントに注入されると、すべての注入が実行され、すべてのイニシャライザがコールされた後にCDIによってそのメソッドがコールされます。
注意: JSR 250で規定されているように、注釈付けされたメソッドがスーパークラスで宣言される場合、宣言するクラスのサブクラスがそのメソッドをオーバーライドしないかぎり、そのメソッドがコールされます。 |
マネージドBeanの破棄の準備では、アプリケーション・コンポーネントがコンテナによって破棄されようとしていることを通知するライフ・サイクル・コールバック・メソッドを指定します。
マネージドBeanの破棄を準備する手順は、次のとおりです。
マネージドBeanクラスまたはそのスーパークラスのいずれかで、マネージドBeanの破棄を準備するメソッドを定義します。
このメソッドでは、Beanが保持していたリソースの解放など、Beanを破棄する前に必要なクリーンアップを実行します。
javax.annotation.PreDestroy
アノテーションで、メソッドの宣言に注釈付けします。
Beanを破棄するためのロジックを開始する前にCDIによってそのメソッドがコールされます。
注意: JSR 250で規定されているように、注釈付けされたメソッドがスーパークラスで宣言される場合、宣言するクラスのサブクラスがそのメソッドをオーバーライドしないかぎり、そのメソッドがコールされます。 |
Beanクラスのメソッド呼出しまたはライフ・サイクル・イベントのインターセプトでは、呼出しまたはイベントにインターセプタ・クラスを割り込みます。インターセプタ・クラスを割り込むと、そのインターセプタ・クラスで定義されている追加のアクションが実行されます。インターセプタ・クラスによって、頻繁に実行されるが、アプリケーションのビジネス・ロジックからは分離されているタスクのコードのメンテナンスが簡素化されます。そのようなタスクの例としては、ロギングと監査があります。
注意: インターセプタ・クラスのプログラミング・モデルは、アプリケーションのビジネス・ロジックから分離されている操作に対して最適化されています。ビジネス・セマンティクスを持つ操作を実行するメソッドをインターセプトするには、「マネージドBeanクラスの装飾」の説明に従ってデコレータ・クラスを使用します。 |
Java EE 5仕様で導入されたインターセプタは、EJBコンポーネント固有です。Java EE 5インターセプタの詳細は、『Oracle WebLogic Server Enterprise JavaBeansの開発』のビジネス・メソッドまたはライフ・サイクル・コールバック・イベントのインターセプタの指定に関する項を参照してください。
CDIでは、次のタイプのJava EE管理対象オブジェクトでインターセプタを使用できます。
CDIマネージドBean
EJBセッションBean
EJBメッセージドリブンBean
注意: CDIではEJBエンティティBeanがサポートされていないため、EJBエンティティBeanでは、インターセプタを使用できません。 |
詳細は、Java EE 6チュートリアルのインターセプタの使用方法に関する項を参照してください。
Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプトには、次の項で説明するタスクが含まれます。
インターセプタ・バインディング・タイプは、インターセプタ・クラスとインターセプトされるBeanを関連付けるアプリケーション定義のアノテーションです。必要なインターセプタのタイプごとにインターセプタ・バインディング・タイプを定義します。
注意: CDIでは、インターセプタ・バインディング・タイプが特定のインターセプタ・クラスに固有でなくても構いません。1つのインターセプタ・バインディング・タイプを複数のインターセプタ・クラスで使用するように定義できます。 |
インターセプタ・バインディング・タイプを定義する手順は、次のとおりです。
インターセプタ・バインディング・タイプを表すJavaアノテーション・タイプを定義します。
javax.interceptor.InterceptorBinding
アノテーションで、アノテーション・タイプの宣言に注釈付けします。
インターセプタ・バインディング・タイプが、実行時に仮想マシンによって保持されることを指定します。
このためには、java.lang.annotation.Retention(RUNTIME)
メタアノテーションを使用します。
インターセプタ・バインディング・タイプを、プログラム要素METHOD
およびTYPE
に適用できることを指定します。
このためには、java.lang.annotation.Target({METHOD, TYPE})
メタアノテーションを使用します。
例9-12 インターセプタ・バインディング・タイプの定義
この例では、@Transactional
インターセプタ・バインディング・タイプを定義します。
package com.example.billpayment.interceptor; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.interceptor.InterceptorBinding; @InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional {}
インターセプタ・クラスは、関連付けられたターゲットBeanクラスで発生するメソッド呼出しまたはライフ・サイクル・イベントへの割込みに使用されます。インターセプタ・クラスでは、ロギングや監査など、頻繁に実行されるが、アプリケーションのビジネス・ロジックからは分離されているタスクのコードを提供します。
インターセプタ・クラスを定義する手順は、次のとおりです。
インターセプタを表すJavaクラスを定義します。
次のアノテーションでクラス宣言に注釈付けします。
クラスに対して定義されているインターセプタ・バインディング・タイプ
1つのインターセプタ・クラスに、任意の数のインターセプタ・バインディング・タイプを適用できます。
注意: CDIでは、インターセプタ・バインディング・タイプが特定のインターセプタ・クラスに固有でなくても構いません。同じインターセプタ・バインディング・タイプを複数のインターセプタ・クラスに適用できます。 |
そのクラス内にインターセプタ・メソッドを実装します。
CDIでは、インターセプタ・メソッドのシグネチャがインターセプトされるメソッドのシグネチャに一致する必要はありません。
クラス内のインターセプタ・メソッドを特定します。
インターセプタ・メソッドは、Beanクラスのメソッド呼出しまたはライフ・サイクル・イベントをインターセプトするときに呼び出されるメソッドです。
インターセプタ・メソッドを特定するには、インターセプタ・メソッドのタイプに適したアノテーションで、メソッドの宣言に注釈付けします。
インターセプタ・メソッドのタイプ | アノテーション |
---|---|
メソッドの呼出し | javax.interceptor.AroundInvoke |
EJBタイムアウト | javax.interceptor.AroundTimeout |
マネージドBeanまたはEJBコンポーネントの初期化 | javax.annotation.PostConstruct |
マネージドBeanまたはEJBコンポーネントの破棄 | javax.annotation.PreDestroy |
ステートフル・セッションBeanのアクティブ化 | javax.ejb.PostActivate |
ステートフル・セッションBeanの非アクティブ化 | javax.ejb.PrePassivate |
注意: 1つのインターセプタ・クラスに、複数のインターセプタ・クラスを含めることができます。ただし、1つのインターセプタ・クラスに含めることができる特定のタイプのインターセプタ・メソッドは1つのみです。 |
例9-13は、インターセプタ・クラスを定義する方法を示します。
例9-13 インターセプタ・クラスの定義
この例では、@Transactional
インターセプタ・バインディング・タイプが定義されるインターセプタ・クラスを定義します。このクラスのmanageTransaction
メソッドは、インターセプタ・メソッドです。@Transactional
インターセプタ・バインディングは、例9-12で定義されています。
package com.example.billpayment.interceptor; import javax.annotation.Resource; import javax.interceptor.*; ... @Transactional @Interceptor public class TransactionInterceptor { @Resource UserTransaction transaction; @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
インターセプトのためのメソッドの特定により、メソッドと、そのメソッドが呼び出されるときに呼び出されるインターセプタが関連付けられます。CDIでは、インターセプトのためにBeanクラスのすべてのメソッドを特定するか、Beanクラスの個別のメソッドのみを特定できます。
インターセプトのためにBeanクラスのすべてのメソッドを特定するには、適切なインターセプタ・バインディング・タイプでBeanクラスの宣言に注釈付けします。
インターセプトのためにBeanクラスの個別のメソッドを特定するには、適切なインターセプタ・バインディング・タイプでそのメソッドの宣言に注釈付けします。
CDIでは、インターセプトされるメソッドのシグネチャがインターセプタ・メソッドのシグネチャに一致する必要はありません。インターセプトされるメソッドの引数と戻りタイプを判別するには、インターセプタがインターセプタ・コンテキストを問い合せる必要があります。したがって、Beanクラスのインタフェースのコンパイル時に何も知識がなくても、Beanクラスの任意のメソッドまたはライフ・サイクル・イベントをインターセプトできます。
注意: Java EE 5インターセプタの実装は、インターセプトされるメソッドのアノテーションで宣言する必要があります。CDIインターセプタは、インターセプタ・バインディングを使用して、インターセプタ・メソッドを特定し、インターセプトされるメソッドをそのインターセプタ・メソッドに関連付けます。インターセプトされるメソッドとインターセプタ・メソッドの両方に、バインディングで注釈付けする必要があります。このようにして、インターセプトされるメソッドとインターセプタ・メソッドは、インターセプタ・バインディングを介してのみ相互に関連付けされます。 |
デフォルトでは、インターセプタは無効です。インターセプタを、メソッドの呼出しおよびイベントに割り込む必要がある場合は、インターセプタを明示的に有効化する必要があります。
インターセプタを有効化する手順は、次のとおりです。
beans.xml
ファイルのinterceptors
要素にインターセプタのclass
要素を追加します。
class
要素に、そのインターセプタの完全修飾クラス名を指定します。
beans.xml
ファイル内のclass
要素の順序が、インターセプタの呼出し順序と一致するようにします。
CDIインターセプタは、beans.xml
ファイルで宣言されている順序で呼び出されます。ejb-jar.xml
ファイル内またはjavax.interceptor.Interceptors
アノテーションによって定義されているインターセプタは、CDIインターセプタの前にコールされます。インターセプタは、CDIデコレータの前にコールされます。
注意: Java EE 5インターセプタは、インターセプトされるメソッドで注釈付けされている順序で呼び出されます。 |
beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください。
例9-16は、インターセプタ・クラスを有効化するためのbeans.xml
ファイルのclass
要素を示します。
例9-16 インターセプタ・クラスの有効化
この例では、インターセプタ・クラスcom.example.billpayment.interceptor.TransactionInterceptor
を有効化します。インターセプタ・クラスは、例9-13で定義されています。
... <interceptors> <class>com.example.billpayment.interceptor.TransactionInterceptor</class> </interceptors> ...
マネージドBeanクラスの装飾により、ビジネス・セマンティクスを持つ操作を実行する装飾されるクラスのメソッドの呼出しをインターセプトできます。どのマネージドBeanクラスも装飾できます。
注意: デコレータ・クラスのプログラミング・モデルは、アプリケーションのビジネス・ロジックを実行する操作に対して最適化されています。アプリケーションのビジネス・ロジックから分離されているメソッドをインターセプトするには、「Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト」の説明に従ってインターセプタ・クラスを使用します。 |
詳細は、Java EE 6チュートリアルのデコレータの使用方法に関する項を参照してください。
マネージドBeanクラスの装飾には、次の項で説明するタスクが含まれます。
デコレータ・クラスは、ビジネス・セマンティクスを持つ操作を実行する装飾されるクラスのメソッドの呼出しをインターセプトします。デコレータ・クラスおよびインターセプタ・クラスは類似しており、どちらもメソッド周辺のインターセプトを提供します。ただし、デコレータ・クラスのメソッドは、装飾されるBeanクラスのインターセプトされるメソッドと同じシグネチャを持ちます。
デコレータ・クラスを定義する手順は、次のとおりです。
装飾対象のBeanクラスと同じインタフェースを実装するJavaクラスを作成します。
装飾されるクラスのいくつかのメソッドのみをインターセプトする場合は、デコレータ・クラスを抽象クラスとして宣言します。クラスを抽象として宣言する場合、装飾対象のBeanクラスのすべてのメソッドを実装する必要はありません。
javax.decorator.Decorator
アノテーションでデコレータ・クラスのクラス宣言に注釈付けします。
インターセプトする装飾されるBeanクラスのメソッドを実装します。
デコレータ・クラスが具体クラスである場合、装飾するBeanクラスのすべてのメソッドを実装する必要があります。
デコレータ・クラスのインターセプトするメソッドが、装飾されるBeanクラスのインターセプトされるメソッドと同じシグネチャを持つようにしてください。
デコレータ・クラスに委任注入ポイントを追加します。
デコレータ・クラスには、委任注入ポイントが1つのみ含まれている必要があります。委任注入ポイントは、装飾されるクラスのインスタンスである委任オブジェクトを、デコレータ・オブジェクトに注入します。
デコレータ・オブジェクトのメソッドが、装飾されるメソッドの実装を処理する方法をカスタマイズできます。CDIでは、デコレータ・オブジェクトが、対応する委任オブジェクトを呼び出すことができますが、これは必須ではありません。したがって、デコレータ・オブジェクトに、対応する委任オブジェクトを呼び出させるかどうかは自由に選択できます。
デコレータ・クラスで、装飾するBeanクラスのインスタンスを注入します。
javax.decorator.Delegate
アノテーションで、注入ポイントに注釈付けします。
注入ポイントに修飾子を適用する必要がある場合は、適用します。
注入ポイントに修飾子を適用すると、デコレータは、注入ポイントの修飾子に一致するBeanクラスのBeanにのみ適用されます。
注意: 装飾されるBeanクラスを定義するために、アノテーションなどの特別な宣言は必要ありません。有効化されたデコレータ・クラスは、委任注入ポイントのBeanタイプと修飾子に一致するBeanクラスまたはセッションBeanに適用されます。 |
例9-17は、デコレータ・クラスの定義を示します。
例9-17 デコレータ・クラスの定義
この例では、デコレータ・クラスDataAccessAuthDecorator
を定義します。このクラスは、タイプDataAccess
のBeanを装飾します。
装飾されるクラスのいくつかのメソッドのみがインターセプトされるため、このクラスは抽象クラスとして宣言します。このクラスは、DataAcess
Beanタイプの装飾される実装の委任インスタンスdelegate
を注入します。
import javax.decorator.*; import javax.inject.Inject; import java.lang.Override; ... @Decorator public abstract class DataAccessAuthDecorator implements DataAccess { @Inject @Delegate DataAccess delegate; @Override public void delete(Object object) { authorize(SecureAction.DELETE, object); delegate.delete(object); } private void authorize(SecureAction action, Object object) { ... } }
デフォルトでは、デコレータ・クラスは無効です。CDIアプリケーションで、デコレータ・クラスを呼び出す必要がある場合は、デコレータ・クラスを明示的に有効化する必要があります。
デコレータ・クラスを有効化する手順は、次のとおりです。
beans.xml
ファイルのdecorators
要素に、デコレータ・クラスのclass
要素を追加します。
class
要素に、そのデコレータ・クラスの完全修飾クラス名を指定します。
beans.xml
ファイル内のclass
要素の順序が、デコレータ・クラスの呼出し順序と一致するようにします。
注意: アプリケーションに対して定義されているインターセプタ・クラスは、そのアプリケーションのデコレータ・クラスの前に呼び出されます。 |
beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください。
例9-18は、デコレータ・クラスを有効化するためのbeans.xml
ファイルのclass
要素を示します。
ELにより、プレゼンテーション・レイヤーのコンポーネントが、アプリケーション・ロジックを実装するマネージドBeanと通信できます。プレゼンテーション・レイヤーのコンポーネントは、通常、JavaServer Faces (JSF)ページおよびJavaServer Pages (JSP)ページです。詳細は、『Oracle WebLogic Server Webアプリケーション、サーブレット、JSPの開発』のJSP式言語に関する項を参照してください。
JSPページおよびJSFページのスクリプト言語では、注入される変数の構文は、これらの言語の組込み変数の構文と同一です。JSPページまたはJSFページに注入されるCDI Beanは、EL名を介してアクセス可能であることが必要です。詳細は、Java EE 6チュートリアルのBeanのEL名の指定に関する項を参照してください。
EL名をCDI Beanクラスに割り当てるには、javax.inject.Named
アノテーションでBeanクラスのクラス宣言に注釈付けします。
名前を指定しない場合、EL名は、最初の文字を小文字にした非修飾クラス名です。たとえば、非修飾クラス名がShoppingCart
である場合、EL名はshoppingCart
です。
名前を指定するには、@Named
アノテーションのvalue
要素を、目的の名前に設定します。
注意: EL名をCDI Beanクラスに割り当てるには、@Named アノテーションでBeanクラス宣言に注釈付けする必要があります。クラスに@Named で注釈付けされていない場合、CDI BeanクラスにEL名は付きません。 |
例9-19は、@Named
アノテーションを使用してEL名をCDI Beanクラスに割り当てる方法を示します。
例9-19 BeanクラスへのEL名の割当て
この例では、EL名cart
をShoppingCart
クラスに割り当てます。
import javax.enterprise.context.SessionScoped; @SessionScoped @Named("cart") public class ShoppingCart { public String getTotal() { ... } ... }
JSPページまたはJSFページがアクセスするBeanは、JavaBeans標準に準拠している必要があります。BeanのEL名を介してJSPページまたはJSFページからCDIマネージドBeanにアクセスするには、JavaBeansコンポーネントの構文に類似した構文を使用します。
例9-20は、JSFページで、ShoppingCart
クラスのインスタンスに、そのクラスに割り当てられたEL名を介してアクセスする方法を示しています。
例9-20 EL名を介したBeanへのアクセス
この例では、ShoppingCart
クラスのインスタンスにアクセスし、JSFページにそのtotal
プロパティの値を表示します。
このプロパティは、例9-19
に示すように、ShoppingCart
クラスのgetTotal getterメソッドによって返されます。
... <h:outputText value="#{cart.total}"/> ...
いくつかのBeanが類似した関数を実行する大規模なアプリケーションでは、場合によっては、同じアノテーションのセットをいくつかのBeanクラスに適用する必要があります。ステレオタイプを定義すると、アノテーションのセットの定義を一度行うのみで済みます。その後、そのステレオタイプを使用して、同じアノテーションのセットを、それらのアノテーションを必要とするすべてのBeanクラスに適用できるようになります。詳細は、Java EE 6チュートリアルのステレオタイプの使用方法に関する項を参照してください。
ステレオタイプの定義と適用には、次の項で説明するタスクが含まれます。
ステレオタイプは、アプリケーション定義のアノテーション・タイプであり、他のアノテーション・タイプが組み込まれています。
ステレオタイプを定義する手順は、次のとおりです。
ステレオタイプを表すJavaアノテーション・タイプを定義します。
次のアノテーションでアノテーション・タイプの宣言に注釈付けします。
ステレオタイプに組み込むその他のアノテーション・タイプ
ステレオタイプには次のアノテーション・タイプを指定できます。
デフォルトのスコープ(「Beanのスコープの定義」を参照)
@Alternative
(「Beanタイプの代替の実装の提供」を参照)
1つ以上のインターセプタ・バインディング(「Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト」を参照)
@Named
(「CDI BeanクラスへのEL名の割当て」を参照)
ステレオタイプが、実行時に仮想マシンによって保持されることを指定します。
このためには、java.lang.annotation.Retention(RUNTIME)
メタアノテーションを使用します。
ステレオタイプをプログラム要素TYPE
に適用できることを指定します。
このためには、java.lang.annotation.Target(TYPE)
メタアノテーションを使用します。
次の例では、ステレオタイプの定義を示します。
例9-21 ステレオタイプの定義
この例では、ステレオタイプ@Action
を定義します。これは、ステレオタイプが注釈付けする各Beanに対して次のことを指定します。
デフォルトのスコープは、そのスコープがスコープ・アノテーションでオーバーライドされていないかぎり、Requestスコープです。
その名前が@Named
アノテーションでオーバーライドされていないかぎり、デフォルトEL名がBeanに割り当てられます。
インターセプタ・バインディング@Secure
および@Transactional
がBeanに適用されます。これらのインターセプタ・バインディングの定義は、この例の範囲外です。
import javax.enterprise.inject.Stereotype; import javax.inject.Named; import javax.enterprise.context.RequestScoped; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; @RequestScoped @Secure @Transactional @Named @Stereotype @Target(TYPE) @Retention(RUNTIME) public @interface Action {}
Beanにステレオタイプを適用するには、適用する各ステレオタイプで、そのBeanのクラス宣言に注釈付けします。Beanには任意の数のステレオタイプを適用できます。Beanに適用するステレオタイプは、「ステレオタイプの定義」の説明に従って定義する必要があります。
例9-22は、Beanにステレオタイプを適用する方法を示します。
例9-22 Beanへのステレオタイプの適用
この例では、ステレオタイプ@Action
および@Mock
をBeanクラスMockLoginAction
に適用します。@Action
ステレオタイプの定義を、例9-21に示します。@Mock
ステレオタイプの定義は、この例の範囲外です。
@Action @Mock public class MockLoginAction extends LoginAction { ... }
実行時に、アプリケーションで、情報を生成する処理が実行されたり、状態の変更が発生し、Bean間の通信が必要となる場合があります。たとえば、アプリケーションで、アプリケーションのアーキテクチャの1つの層のステートフルBeanがそれらの内部状態を、別の層で発生する状態の変更と同期することが必要な場合があります。
イベントを使用すると、Beanはコンパイル時の依存関係なしにこの情報を通信できます。1つのBeanでイベントを定義し、別のBeanでイベントを送信し、さらに別のBeanでそのイベントを処理できます。これらのBeanは、それぞれ別のパッケージに含めることができ、アプリケーションの別の層に含めることもできます。詳細は、Java EE 6チュートリアルのイベントの使用方法に関する項を参照してください。
Bean間の通信のためのイベントの使用には、次の項で説明するタスクが含まれます。
イベント・タイプは、Bean間で通信する情報を表すJavaクラスです。たとえば、イベント・タイプは、ステートフルBeanがアプリケーションの別の層における状態の変更と同期する必要がある状態情報を表す場合があります。
Bean間で通信する変更のセットごとにイベントのタイプを定義します。
イベント・タイプを定義する手順は、次のとおりです。
そのイベント・タイプを表すJavaクラスを定義します。
そのクラスが、次の要件を満たすようにします。
クラスが具体Javaクラスとして宣言されています。
クラスにタイプ変数がありません。
イベントのイベント・タイプには、イベント・オブジェクトのランタイム・クラスのすべてのスーパークラスとインタフェースが含まれます。イベント・タイプには、タイプ変数を含めないでください。どのJavaタイプも監視対象のイベント・タイプにできます。
必要であれば、このタイプのイベントをさらに区別するための修飾子を定義します。詳細は、「Beanタイプの実装に対する修飾子の定義」を参照してください。
クラスにコードを指定して、クラスからインスタンス化されるイベント・オブジェクトのイベント・ペイロードを移入します。
イベント・ペイロードとは、そのイベントに含める情報です。getterおよびsetterメソッドとともにJavaBeansプロパティを使用して、イベント・ペイロード内の情報のアイテムを表すことができます。
処理に応じて発生した変更を通信するには、アプリケーションが、処理を実行するときに正しいタイプのイベントを送信する必要があります。CDIは、実行時にアプリケーション・コードがイベントを送信し、関連付けられた修飾子を選択できるようにする事前定義済イベント・ディスパッチャ・オブジェクトを提供しています。
イベントを送信する手順は、次のとおりです。
送信するイベント・タイプのインスタンスを取得します。
送信するイベント・オブジェクトのイベント・ペイロードを移入するためのイベント・インスタンスのメソッドをコールします。
パラメータ化javax.enterprise.event.Event
インタフェースのインスタンスを注入します。
修飾イベントを送信する場合、イベント修飾子で注入ポイントに注釈付けします。
注入されるEvent
インスタンスのfire
メソッドをコールします。
fire
メソッドへのコールで、送信するイベント・インスタンスをパラメータとして渡します。
例9-23は、イベントを送信する方法を示します。
例9-23 イベントの送信
この例では、修飾子@LoggedIn
で、タイプUser
のイベントのインスタンスを注入します。fire
メソッドは、@LoggedIn
修飾子が適用されるUser
イベントのみを送信します。
import javax.enterprise.event.Event; import javax.enterprise.context.SessionScoped; import javax.inject.Inject; import java.io.Serializable; @SessionScoped public class Login implements Serializable { @Inject @LoggedIn Event<User> userLoggedInEvent; private User user; public void login(Credentials credentials) { //... use credentials to find user if (user != null) { userLoggedInEvent.fire(user); } } ... }
どのCDIマネージドBeanクラスもイベントを処理できます。
イベントを処理する手順は、次のとおりです。
Beanクラスでは、イベントを処理するメソッドを定義します。
注意: 修飾子をイベント・タイプに適用する場合、修飾されるタイプごとに1つのメソッドを定義します。 |
メソッドのシグネチャで、メソッドにイベントを渡すためのパラメータを定義します。
パラメータのタイプは、必ずイベントのJavaタイプと同一になるようにします。
javax.enterprise.event.Observes
アノテーションで、メソッド・シグネチャのパラメータに注釈付けします。
必要であれば、メソッドが条件付であるかトランザクションであるかを指定する@Observes
アノテーションの要素を設定します。詳細は、Java EE 6チュートリアルのオブザーバ・メソッドを使用したイベントの処理に関する項を参照してください。
イベント・タイプが修飾されている場合は、注釈付けされるパラメータに修飾子を適用します。
メソッド本体に、イベント・オブジェクトのイベント・ペイロードを処理するためのコードを指定します。
例9-24は、特定のタイプの修飾されたイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。例9-25は、特定のタイプのすべてのイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。
CDIは、次のインタフェースを実装する事前定義済Beanを提供しています。
javax.transaction.UserTransaction
Java Transaction API (JTA)ユーザー・トランザクション。
java.security.Principal
個人、企業、ログインIDなどのエンティティを表すプリンシパルの抽象的な観念。
プリンシパルは、現在のコール元のIDを表します。注入されたプリンシパルにアクセスする場合はいつでも、それは常に現在のコール元のIDを表します。
たとえば、プリンシパルは、初期化の際にフィールドに注入されます。後で、プリンシパルが注入されたオブジェクトに対して、注入されたプリンシパルを使用するメソッドがコールされます。この状況では、注入されたプリンシパルは、メソッドが実行されるときの現在のコール元のIDを表します。
javax.validation.Validator
Beanインスタンスのバリデータ。
このインタフェースを実装するBeanによって、デフォルトのBean検証ValidatorFactory
オブジェクトのValidator
オブジェクトを注入できます。
javax.validation.ValidatorFactory
初期化されたValidator
インスタンスを返すファクトリ・クラス。
このインタフェースを実装するBeanによって、デフォルトのBean検証ValidatorFactory
オブジェクトを注入できます。
事前定義済Beanを注入するには、javax.annotation.Resource
アノテーションを使用して、Beanのインスタンスを取得することで、注入ポイントを作成します。Beanタイプについては、Beanによって実装されるインタフェースのクラス名を指定します。
事前定義済Beanは、Dependentスコープおよび事前定義済のデフォルト修飾子@Default
が指定されて注入されます。
リソースの注入の詳細は、Java EE 6チュートリアルのリソースの注入に関する項を参照してください。
例9-26は、@Resource
アノテーションを使用して事前定義済Beanを注入する方法を示します。
例9-26 事前定義済Beanの注入
この例では、サーブレット・クラスTransactionServlet
にユーザー・トランザクションを注入します。ユーザー・トランザクションは、javax.transaction.UserTransaction
インタフェースを実装する事前定義済Beanのインスタンスです。
import javax.annotation.Resource; import javax.servlet.http.*; ... public class TransactionServlet extends HttpServlet { @Resource UserTransaction transaction; ... }
Java EE 5のリソース注入は、構成の文字列に依存しています。通常、これらの文字列は、オブジェクトが作成されるときに解決されるJNDI名です。CDIでは、注入ポイントで指定されているJavaタイプに基づいてBeanクラスを選択することで、Beanの型保証注入が保証されます。
CDI Beanクラスでも、データ・ソース、Java Message Service (JMS)リソース、Webサービス参照など実際のリソースにアクセスするには、Java EE 5のリソース注入が必要です。CDI Beanクラスは、Java EE 5のリソース注入を使用できるため、プロデューサ・フィールドを使用して、Java EE 5のリソース注入への依存を最小限にできます。このようにすることで、CDIでは、適切なリソースにアクセスするために必要な構成をカプセル化する方法が簡素化されます。
Java EE 5のリソース注入への依存を最小限にする手順は、次のとおりです。
アプリケーション内の1箇所のみで、Java EE 5のリソース注入を使用します。
プロデューサ・フィールドを使用して、注入されるリソース・タイプをCDI Beanに変換します。
このCDI Beanは、他のCDI Beanと同様にアプリケーションに注入できます。
プロデューサ・フィールドの詳細は、「プロデューサ・フィールドの定義」を参照してください。
例9-27は、Java EE 5アノテーションを使用してリソースを注入する方法を示します。例9-28は、CDIプロデューサ・フィールドとJava EE 5のリソース注入を結合することで、同じリソースのセットを注入する方法を示します。
例9-27 リソースを注入するためのJava EE 5アノテーションの使用方法
import javax.annotation.Resource; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceUnit; import javax.ejb.EJB; import javax.xml.ws.WebServiceRef; ... public class SomeClass { @WebServiceRef(lookup="java:app/service/PaymentService") PaymentService paymentService; @EJB(ejbLink="../payment.jar#PaymentService") PaymentService paymentService; @Resource(lookup="java:global/env/jdbc/CustomerDatasource") Datasource customerDatabase; @PersistenceContext(unitName="CustomerDatabase") EntityManager customerDatabasePersistenceContext; @PersistenceUnit(unitName="CustomerDatabase") EntityManagerFactory customerDatabasePersistenceUnit; ... }
例9-28 プロデューサ・フィールドとJava EE 5のリソース注入の結合
SomeClass
クラスの宣言は、このBeanのスコープをApplicationに設定する@ApplicationScoped
で注釈付けされています。@Dependent
スコープは、プロデューサ・フィールドに暗黙的に適用されます。
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import javax.annotation.Resource; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceUnit; import javax.ejb.EJB; javax.xml.ws.WebServiceRef; ... @ApplicationScoped public class SomeClass { @Produces @WebServiceRef(lookup="java:app/service/PaymentService") PaymentService paymentService; @Produces @EJB(ejbLink="../their.jar#PaymentService") PaymentService paymentService; @Produces @CustomerDatabase @Resource(lookup="java:global/env/jdbc/CustomerDatasource") Datasource customerDatabase; @Produces @CustomerDatabase @PersistenceContext(unitName="CustomerDatabase") EntityManager customerDatabasePersistenceContext; @Produces @CustomerDatabase @PersistenceUnit(unitName="CustomerDatabase") EntityManagerFactory customerDatabasePersistenceUnit; ... }
CDIでは、CDIとの一貫性を保つようにCDIアプリケーションでJava EEリソースを使用できます。このようにJava EEリソースを使用するには、そのリソースをCDI Beanとして他のBeanに注入します。
例9-29は、Java EEリソースをCDI Beanとして別のBeanに注入する方法を示します。
例9-29 別のBeanへのJava EEリソースのCDI Beanとしての注入
この例では、永続性ユニット・リソースをRequestスコープを持つBeanに注入します。
import javax.enterprise.context.RequestScoped; import javax.enterprise.inject.Inject; @RequestScoped public class SomeOtherClass { ... @Inject @CustomerDatabase private EntityManagerFactory emf; ... }
別のクラス、たとえばYetAnotherClass
は、タイプSomeOtherClass
のフィールドを注入できます。SomeOtherClass
のインスタンスが、現在のリクエスト・コンテキストに存在していない場合は、CDIによって次の一連の処理が実行されます。
SomeOtherClass
のインスタンスの作成
例9-28のプロデューサ・フィールドを使用することによるエンティティ・マネージャ・ファクトリへの参照の注入
現在のリクエスト・コンテキストでのSomeOtherClass
の新しいインスタンスの保存
どの場合も、CDIによって、SomeOtherClass
のこのインスタンスへの参照が、YetAnotherClass
のフィールドに注入されます。リクエスト・コンテキストが破棄されるときに、SomeOtherClass
のインスタンスおよびエンティティ・マネージャ・ファクトリへのその参照が破棄されます。
WebLogic Serverでは、埋込みリソース・アダプタおよびグローバル・リソース・アダプタでのCDIがサポートされています。CDIに対してリソース・アダプタを有効化するには、リソース・アダプタのパッケージ化されたアーカイブのMETA-INF
ディレクトリにbeans.xml
ファイルを配置します。beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください。
リソース・アダプタのすべてのクラスを、注入に使用できます。次のクラスを除いて、リソース・アダプタのすべてのクラスをCDIマネージドBeanにできます。
リソース・アダプタBean。これらのBeanは、javax.resource.spi.Connector
アノテーションで注釈付けされているか、リソース・アダプタ・デプロイメント記述子ra.xml
で対応する要素として宣言されているクラスです。
マネージド接続ファクトリBean。これらのBeanは、javax.resource.spi.ConnectionDefinition
アノテーションまたはjavax.resource.spi.ConnectionDefinitions
アノテーションで注釈付けされているか、ra.xml
で対応する要素として宣言されているクラスです。
アクティブ化仕様Bean。これらのBeanは、javax.resource.spi.Activation
アノテーションで注釈付けされているか、ra.xml
で対応する要素として宣言されてるクラスです。
管理対象オブジェクトBean。これらのBeanは、javax.resource.spi.AdministeredObject
アノテーションで注釈付けされているか、ra.xml
で対応する要素として宣言されているクラスです。
CDIアプリケーションを構成すると、そのアプリケーションに対してCDIサービスが有効化されます。CDIアプリケーションは、そのアプリケーションがCDIアプリケーションとして識別されるように構成する必要があります。CDIマネージドBeanを定義するために、アノテーションなどの特別な宣言は必要ありません。CDIアプリケーションのパッケージ化のために特に定義されているモジュール・タイプはありません。
CDIアプリケーションを構成するには、beans.xml
という名前のファイルを、アプリケーションのパッケージ化されたアーカイブに含めます。beans.xml
ファイルは、eXtensible Markup Language (XML)スキーマbeans_1_0.xsd
のインスタンスである必要があります。
アプリケーションで代替、インターセプタ、デコレータのいずれも使用しない場合は、beans.xml
ファイルを空にできます。ただし、beans.xml
ファイルは空であっても提供する必要があります。
CDIアプリケーションで代替、インターセプタまたはデコレータを使用する場合は、それらのアイテムをbeans.xml
ファイルで宣言することでそれらを有効化する必要があります。詳細は、次を参照してください:
beans.xml
ファイルの必須の場所は、アプリケーションのタイプに応じて異なります。
Webアプリケーションの場合は、beans.xml
ファイルは、WEB-INF
ディレクトリ内に配置してください。
EJBモジュール、リソース・アーカイブ(RAR)ファイル、アプリケーション・クライアントJARファイル、またはライブラリJARファイルの場合は、beans.xml
ファイルはMETA-INF
ディレクトリ内に配置してください。
CDI Beanアーカイブは、EJBモジュールのlib
ディレクトリに含めることができます。EJBモジュールのlib
ディレクトリの各CDI BeanアーカイブのMETA-INF
ディレクトリにbeans.xml
ファイルを含める必要があります。
例9-30は、CDIアプリケーションを構成するためのbeans.xml
ファイルを示します。
例9-30 CDIアプリケーションを構成するためのbeans.xmlファイル
この例では、次のクラスを有効化することで、CDIアプリケーションを構成します。
代替の実装com.example.orderprocessor.MockOrderImpl
インターセプタ・クラスcom.example.billpayment.interceptor.TransactionInterceptor
デコレータ・クラスcom.example.billpayment.decorator.DataAccessAuthDecorator
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>com.example.orderprocessor.MockOrderImpl</class> </alternatives> <interceptors> <class>com.example.billpayment.interceptor.TransactionInterceptor</class> </interceptors> <decorators> <class>com.example.billpayment.decorator.DataAccessAuthDecorator</class> </decorators> </beans>
CDIは、フレームワーク、拡張、および他のテクノロジとの統合の基盤となることを目的としています。したがって、CDIは、次のようなCDIへのポータブルな拡張の開発を可能にするSPIを公開しています。
ビジネス・プロセス管理エンジンとの統合
Spring、Seam、GWT、Wicketなどサード・パーティのフレームワークとの統合
CDIプログラミング・モデルに基づいた新しいテクノロジ
CDIへのポータブルな拡張の開発を可能にするSPIは、javax.enterprise.inject.spi
パッケージで提供されています。
CDIの拡張のコードは、CDIフレームワークによって送信されるイベントを処理できます。
詳細は、『JSR 299: Contexts and Dependency Injection for the Java EE platform』の「Portable extensions」を参照してください。