9 Contexts and Dependency Injection for the Java EE Platformの使用方法
この章の内容は次のとおりです。
- CDI for the Java EE Platformについて
Java EEプラットフォーム仕様のCDIは、以前はWeb Beanと呼ばれていました。CDI注入により、WebアプリケーションでJSFテクノロジとともにマネージドBeanを簡単に使用できるようになります。 - マネージドBeanの定義
マネージドBeanは、CDIアプリケーションの基本コンポーネントであり、CDIによって作成および管理できるBeanを定義します。 - Beanの注入
自身で定義するBeanを使用するには、それらを、JavaServer Facesなどのアプリケーションが使用できる別のBeanに注入します。 - Beanのスコープの定義
Beanのスコープは、そのBeanを使用するアプリケーションとユーザーの対話の期間を定義します。Webアプリケーションが、別のBeanクラスを注入するBeanを使用できるようにするには、そのBeanがアプリケーションとユーザーの対話の期間にわたって状態を保持できるようにする必要があります。 - 注入ポイントでのBeanのスコープのオーバーライド
注入ポイントでのBeanのスコープのオーバーライドにより、アプリケーションは、デフォルト・スコープ@Dependent
を持つBeanの新しいインスタンスをリクエストできます。@Dependent
のスコープは、そのBeanのライフ・サイクルを、そのBeanの注入先のオブジェクトのライフ・サイクルにすることを指定します。 - 修飾子の使用方法
修飾子によって、特定のBeanタイプの実装を複数提供できます。 - Beanタイプの代替の実装の提供
エンタープライズ・アプリケーションの開発、テスト、および本番デプロイメントの各環境は、大きく異なる場合があります。構成、リソースの可用性、およびパフォーマンスの要件の相違により、1つの環境に適したBeanクラスが、別の環境には合わないことがあります。Beanタイプの代替の実装を提供することにより、そのような異なる要件を満たすためにデプロイメント時にアプリケーションを変更できます。 - セッションBeanへのスコープと修飾子の適用
CDIでは、スコープおよび修飾子をセッションBeanに適用できます。 - プロデューサ・メソッド、ディスポーザ・メソッド、およびプロデューサ・フィールドの使用方法
プロデューサ・メソッドは、注入可能なオブジェクトを生成するメソッドです。ディスポーザ・メソッドは、アプリケーションが、プロデューサ・メソッドから返されたオブジェクトに、カスタマイズされたクリーンアップを実行できるようにします。プロデューサ・フィールドは、オブジェクトを生成するBeanのフィールドです。 - マネージドBeanの初期化と破棄の準備
CDIマネージドBeanクラスおよびそれらのスーパークラスでは、マネージドBeanの初期化と破棄の準備のためのアノテーションがサポートされています。 - Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト
Beanクラスのメソッド呼出しまたはライフ・サイクル・イベントのインターセプトでは、呼出しまたはイベントにインターセプタ・クラスに割り込みます。インターセプタ・クラスを割り込むと、そのインターセプタ・クラスで定義されている追加のアクションが実行されます。 - マネージドBeanクラスの装飾
マネージドBeanクラスの装飾により、ビジネス・セマンティクスを持つ操作を実行する装飾されるクラスのメソッドの呼出しをインターセプトできます。 - CDI BeanクラスへのEL名の割当て
ELにより、プレゼンテーション・レイヤーのコンポーネントが、アプリケーション・ロジックを実装するマネージドBeanと通信できます。 - ステレオタイプの定義と適用
いくつかのBeanが類似した関数を実行する大規模なアプリケーションでは、場合によっては、同じアノテーションのセットをいくつかのBeanクラスに適用する必要があります。ステレオタイプを定義すると、アノテーションのセットの定義を一度行うのみで済みます。 - Bean間の通信のためのイベントの使用方法
イベントを使用すると、Beanはコンパイル時の依存関係なしに情報を通信できます。 - 事前定義済Beanの注入
事前定義済Beanは、Dependentスコープおよび事前定義済のデフォルト修飾子@Default
が指定されて注入されます。 - リソースの注入と修飾
Java EE 5のリソース注入は、構成の文字列に依存しています。通常、これらの文字列は、オブジェクトが作成されるときに解決されるJNDI名です。CDIでは、注入ポイントで指定されているJavaタイプに基づいてBeanクラスを選択することで、Beanの型保証注入が保証されます。 - JCAテクノロジでのCDIの使用方法
WebLogic Serverでは、埋込みリソース・アダプタおよびグローバル・リソース・アダプタでのCDIがサポートされています。CDIに対してリソース・アダプタを有効化するには、リソース・アダプタのパッケージ化されたアーカイブのMETA-INF
ディレクトリにbeans.xml
ファイルを配置します。 - CDIアプリケーションの構成
CDIアプリケーションを構成することにより、アプリケーションのCDIサービスが有効になります。CDIアプリケーションを構成して、アプリケーションをCDIアプリケーションとして識別する必要があります。CDIマネージドBeanを定義するために、アノテーションなどの特別な宣言は必要ありません。CDIアプリケーションのパッケージ化のために特に定義されているモジュール・タイプはありません。 - CDIの有効化および無効化
ドメインのCDIはデフォルトで有効になっています。 ただし、CDIを使用しない場合でも、WebLogic Serverでアプリケーションをデプロイする際に発生するCDIの初期化がいくつかあります。 CDIを使用しないアプリケーションのデプロイメント・パフォーマンスを最大化するために、CDIを無効にすることができます。 - 暗黙的Beanの検出
CDI 1.1およびJava EE 7では、暗黙的Beanアーカイブの概念を導入しました。暗黙的Beanアーカイブは、beans.xml
ファイルを持たないJARファイルまたはWARファイルのアーカイブです。CDIによって管理できるBeanを持ちます。 - サード・パーティのポータブルな拡張のサポート
CDIは、フレームワーク、拡張、および他のテクノロジとの統合の基盤となることを目的としています。 - 組込みアノテーション・リテラルの使用
CDI 2.0では、アノテーションのインスタンスの作成に使用できる新しい組込みアノテーション・リテラルが導入されています。 - コンフィギュレータ・インタフェースの使用
CDI 2.0では、CDIオブジェクトを動的に定義または変更するために使用できる、新しいコンフィギュレータ・インタフェースがいくつか導入されました。 - CDIコンテナのブートストラップ
CDI 2.0には、Java SEのCDIコンテナをブートストラップするための標準APIがあります。SeContainerInitializer
抽象クラスとその静的メソッドnewInstance()
を使用して、CDIコンテナを明示的にブートストラップする必要があります。
CDI for the Java EE Platformについて
Java EEプラットフォーム仕様のCDIは、以前はWeb Beanと呼ばれていました。CDI注入により、WebアプリケーションでJSFテクノロジとともにマネージドBeanを簡単に使用できるようになります。
CDIは、Java Specification Request (JSR) 365: Contexts and Dependency Injection for the Java 2.0によって指定されています。CDIは、次の関連する仕様を使用します。
-
Java EE 8のマネージドBeanの仕様。これは、『JSR 366: Java Platform, Enterprise Edition 8 (Java EE 8) Specification』の一部です。
-
インターセプタの仕様。これは、『JSR 345: Enterprise JavaBeans 3.2』の一部です。
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 8チュートリアルのJava EEプラットフォームのコンテキストおよび依存関係インジェクションの概要に関する項を参照してください。
CDI 2.0の例
-
非同期イベント – 非同期イベントの生成方法と、シングルトンEJBによるこれらのイベントの消費方法を示します。
-
オブザーバ順序付け – シングルトンEJBが優先度に従ってイベントを消費する方法を示します。
-
インターセプト・ファクトリ – InterceptionFactoryにより、指定されたアノテーションを動的に追加してクラス・インスタンスを生成する方法を示します。
詳細は、WebLogic Server配布キットのCDI 2.0の例Oracle_HOME\wlserver\samples\server\examples\src\examples\javaee8\cdi
を参照してください。この場合、ORACLE_HOME
は、WebLogic Serverをインストールしたディレクトリを表します。『Oracle WebLogic Serverの理解』の「サンプル・アプリケーションおよびサンプル・コード」を参照してください
CDI 1.1の例
CDIの使用方法を示すJava EE 7の例は、Oracle_HOME\wlserver\samples\server\examples\src\examples\javaee7\cdi
にインストールされたcdiサンプル・アプリケーションで提供されています。この場合、ORACLE_HOME
は、WebLogic Serverをインストールしたディレクトリを表します。『Oracle WebLogic Serverの理解』の「サンプル・アプリケーションおよびサンプル・コード」を参照してください
マネージドBeanの定義
マネージドBeanは、CDIアプリケーションの基本コンポーネントであり、CDIによって作成および管理できるBeanを定義します。
Beanは、CDIによって作成および管理できるオブジェクトのソースです。Java EE 8チュートリアルのBeanに関する項を参照してください。
マネージドBeanを定義するには、次の条件のいずれかを満たす最上位レベルのプレーンな従来型Javaオブジェクト(POJO)クラスを定義します。
-
このクラスは、他のJava EE仕様によってマネージドBeanとなるように定義されています。
-
このクラスは、Java EE 8チュートリアルのCDIマネージドBeanに関する項にリストされているJSR 346で必要とされる条件をすべて満たします。
ノート:
マネージドBeanを定義するために、アノテーションなど特別な宣言は必要ありません。アプリケーションのマネージドBeanを注入に使用できるようにするには、「CDIアプリケーションの構成」の説明に従ってアプリケーションを構成する必要があります
Beanの注入
自身で定義するBeanを使用するには、それらを、JavaServer Facesなどのアプリケーションが使用できる別のBeanに注入します。
Java EE 8チュートリアルのBeanの注入に関する項を参照してください。
CDIでは、Bean名ではなく、注入ポイントで指定されているJavaの型に基づいてBeanクラスを選択することで、型を保証してBeanを注入できます。CDIでは、注入ポイントのJavaの型からBeanを注入する場所も判別されます。
この点において、CDI BeanインジェクションはJava EE 5仕様で導入されたリソース・インジェクションとは異なり、リソースの文字列名から呼び出すためにリソースを選択します。たとえば、javax.annotation.Resourceアノテーションで注入されるデータ・ソースは、その文字列名によって識別されます。
Beanを注入するには、注入するBeanを使用するクラス内に注入ポイントを作成することで、Beanのインスタンスを取得します。javax.inject.Inject
アノテーションで、次のプログラム要素の1つに注釈付けすることで注入ポイントを作成します。
-
インスタンス・クラス・フィールド
-
イニシャライザ・メソッド・パラメータ
-
Beanコンストラクタ・パラメータ
例9-1は、@Inject
アノテーションを使用してBeanを別のBeanに注入する方法を示します。
例9-1 別のBeanへのBeanの注入
この例では、インスタンス・クラス・フィールドに注釈付けして、BeanクラスGreeting
のインスタンスをクラスPrinter
に注入します。
import javax.inject.Inject; ... public class Printer { @Inject Greeting greeting; ... }
Beanのスコープの定義
Beanのスコープは、そのBeanを使用するアプリケーションとユーザーの対話の期間を定義します。Webアプリケーションが、別のBeanクラスを注入するBeanを使用できるようにするには、そのBeanがアプリケーションとユーザーの対話の期間にわたって状態を保持できるようにする必要があります。
Beanのスコープを定義するには、Beanのクラス宣言にそのスコープのアノテーションを付けます。javax.enterprise.context
パッケージは、次のスコープを宣言します。
-
@RequestScoped
-
@SessionScoped
-
@ApplicationScoped
-
@ConversationScoped
-
@Dependent
これらのスコープの詳細は、Java EE 8チュートリアルのスコープの使用方法に関する項を参照してください。
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のスコープのオーバーライド
注入ポイントでのBeanのスコープのオーバーライドにより、アプリケーションは、デフォルト・スコープ@Dependent
を持つBeanの新しいインスタンスをリクエストできます。@Dependent
のスコープは、そのBeanのライフ・サイクルを、そのBeanの注入先のオブジェクトのライフ・サイクルにすることを指定します。
CDIコンテナは、インスタンスにその他のライフ・サイクル管理を提供しません。スコープの詳細は、「Beanのスコープの定義」を参照してください
ノート:
Beanのスコープのオーバーライドによる影響は、特にオーバーライドされるスコープが@Request
や@Session
の場合に、予期できない望ましくないものになることがあります。
注入ポイントでBeanのスコープをオーバーライドするには、@Inject
アノテーションのかわりにjavax.enterprise.inject.New
アノテーションを使用することでBeanを注入します。@Inject
アノテーションの詳細は、「Beanの注入」を参照してください
修飾子の使用方法
修飾子によって、特定のBeanタイプの実装を複数提供できます。
修飾子を使用する場合、開発時に複数の実装の中から選択します。Java EE 8チュートリアルの修飾子の使用に関する項を参照してください。
ノート:
デプロイメント時に複数の代替の実装の中から選択するには、「Beanタイプの代替の実装の提供」の説明に従って代替を使用します
修飾子の使用方法には、次の項で説明するタスクが含まれます。
Beanタイプの実装に対する修飾子の定義
修飾子は、アプリケーションによって定義されるアノテーションであり、Beanタイプの実装の識別を可能にします。提供するBeanタイプの実装ごとに修飾子を1つ定義します。
修飾子は、Beanタイプの複数の実装を提供し、かつ代替を使用していない場合にのみ定義します。Beanタイプに対して修飾子が定義されていない場合、そのタイプのBeanが注入されるときにCDIによって事前定義済修飾子@Default
が適用されます。
ノート:
CDIでは、修飾子が特定のBeanに一意である必要はありません。1つの修飾子を複数のBeanタイプに定義できます。
修飾子を定義するには:
次の例では、修飾子@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に修飾子を適用すると、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を注入するには、注入ポイントを作成し、その注入ポイントに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; ... }
親トピック: 修飾子の使用方法
Beanタイプの代替の実装の提供
エンタープライズ・アプリケーションの開発、テスト、および本番デプロイメントの各環境は、大きく異なる場合があります。構成、リソースの可用性、およびパフォーマンスの要件の相違により、1つの環境に適したBeanクラスが、別の環境には合わないことがあります。Beanタイプの代替の実装を提供することにより、そのような異なる要件を満たすためにデプロイメント時にアプリケーションを変更できます。
同じアプリケーションでも、デプロイメント・シナリオの相違によって、異なるビジネス・ロジックが必要とされる場合もあります。たとえば、注文処理アプリケーションでは、国固有の消費税法によって国固有の消費税のビジネス・ロジックが必要な場合もあります。
CDIでは、対応するプライマリの実装のかわりに、任意の数の代替のBeanタイプの実装から注入するものを選択できます。Java EE 8チュートリアルのCDIアプリケーションでの代替の使用に関する項を参照してください。
ノート:
開発時に複数の代替の実装から選択するには、「修飾子の使用方法」の説明に従って修飾子を使用します
Beanタイプの代替の実装の提供には、次の項で説明するタスクが含まれます。
Beanタイプの代替の実装の定義
Beanタイプの代替の実装を定義するには:
次の例では、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 { ... }
親トピック: Beanタイプの代替の実装の提供
アプリケーションに対するBeanタイプの代替の実装の選択
デフォルトでは、CDIはアプリケーションへの注入にBeanタイプのプライマリの実装を選択します。代替の実装を注入する必要がある場合は、明示的にその代替を選択する必要があります。
アプリケーションに対して代替の実装を選択するには:
beans.xml
ファイルのalternatives
要素に、代替のclass
要素を追加します。class
要素に、代替の完全修飾クラス名を指定します。
beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください
例9-16は、Beanタイプの代替の実装を選択するためのbeans.xml
ファイルのclass
要素を示しています。
例9-10 Beanタイプの代替の実装の選択
この例では、代替の実装com.example.orderprocessor.MockOrderImpl
を選択します。
... <alternatives> <class>com.example.orderprocessor.MockOrderImpl</class> </alternatives> ...
親トピック: Beanタイプの代替の実装の提供
セッションBeanへのスコープと修飾子の適用
CDIでは、スコープおよび修飾子をセッションBeanに適用できます。
セッションBeanは、次の要件のいずれかを満たすEJBコンポーネントです。
-
Beanを実装するクラスには、次のいずれかのアノテーションが付いています。
-
javax.ejb.Singleton
。シングルトン・セッションBeanを指定します。 -
javax.ejb.Stateful
。ステートフル・セッションBeanを指定します。 -
javax.ejb.Stateless
。ステートレス・セッションBeanを指定します。
-
-
そのBeanが、
ejb-jar.xml
デプロイメント記述子ファイルにリストされています。
セッションBeanの詳細は、次のドキュメントを参照してください。
セッションBeanへのスコープの適用
CDIによりセッションBeanに適用できるスコープは、表9-1に示すようにセッションBeanのタイプに応じて異なります。
表9-1 セッションBeanに適用できるCDIスコープ
セッションBeanタイプ | 適用できるスコープ |
---|---|
シングルトン |
次のスコープのいずれかです。
|
ステートフル |
任意 |
ステートレス |
Dependent |
CDIにおけるスコープの詳細は、「Beanのスコープの定義」を参照してください
CDIで、ステートフル・セッションBeanへの参照が注入されるときは、CDIによってBeanが作成され、Beanのフィールドが注入され、そのスコープに応じてステートフル・セッションBeanが管理されます。コンテキストを破棄するときは、CDIによってステートフル・セッションBeanの削除メソッドがコールされ、そのBeanが削除されます。
親トピック: セッションBeanへのスコープと修飾子の適用
セッションBeanへの修飾子の適用
CDIでは、任意の修飾子をセッションBeanに適用できます。CDIでは、セッションBeanに適用できる修飾子のタイプに制限はありません。CDIにおける修飾子の詳細は、「修飾子の使用方法」を参照してください
親トピック: セッションBeanへのスコープと修飾子の適用
プロデューサ・メソッド、ディスポーザ・メソッド、およびプロデューサ・フィールドの使用方法
プロデューサ・メソッドは、注入可能なオブジェクトを生成するメソッドです。ディスポーザ・メソッドは、アプリケーションが、プロデューサ・メソッドから返されたオブジェクトに、カスタマイズされたクリーンアップを実行できるようにします。プロデューサ・フィールドは、オブジェクトを生成するBeanのフィールドです。
プロデューサ・フィールドは、プロデューサ・メソッドの単純な代替です。
Java EE 8チュートリアルのCDIアプリケーションでのプロデューサ・メソッド、プロデューサ・フィールドおよびディスポーザ・メソッドの使用に関する項を参照してください。
プロデューサ・メソッドの定義
プロデューサ・メソッドにより、アプリケーションは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は起動しません。
プロデューサ・フィールドには、ディスポーザはありません。
マネージドBeanの初期化と破棄の準備
CDIマネージドBeanクラスおよびそれらのスーパークラスでは、マネージドBeanの初期化と破棄の準備のためのアノテーションがサポートされています。
これらのアノテーションは、『JSR 250: Common Annotations for the Java Platform』で定義されています。詳細は、Java EEアノテーションと依存関係インジェクションの使用を参照してください。
マネージドBeanの初期化
マネージドBeanの初期化では、依存関係インジェクションの後、クラスがサービスを開始する前にCDIフレームワークがコールする必要があるライフ・サイクル・コールバック・メソッドを指定します。
マネージドBeanを初期化するには:
親トピック: マネージドBeanの初期化と破棄の準備
マネージドBeanの破棄の準備
マネージドBeanの破棄の準備では、アプリケーション・コンポーネントがコンテナによって破棄されようとしていることを通知するライフ・サイクル・コールバック・メソッドを指定します。
マネージドBeanの破棄を準備するには:
親トピック: マネージドBeanの初期化と破棄の準備
Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト
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 8チュートリアルのCDIアプリケーションでのインターセプタの使用に関する項を参照してください。
Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプトには、次の項で説明するタスクが含まれます。
- インターセプタ・バインディング・タイプの定義
- インターセプタ・クラスの定義
- インターセプトのためのメソッドの特定
- インターセプタの有効化
- プロデューサへのインターセプタの適用
CDI 1.xでは、インターセプタはプロデューサBeanにバインドされません。CDI 2.0では、インタフェースjavax.enterprise.inject.spi.InterceptionFactory<T>
が導入され、それにより、インターセプタをプロデューサ・メソッドの戻り値にプログラムで適用できるようになります。
インターセプタ・バインディング・タイプの定義
インターセプタ・バインディング・タイプは、インターセプタ・クラスとインターセプトされるBeanを関連付けるアプリケーション定義のアノテーションです。必要なインターセプタのタイプごとにインターセプタ・バインディング・タイプを定義します。
ノート:
CDIでは、インターセプタ・バインディング・タイプが特定のインターセプタ・クラスに固有でなくても構いません。1つのインターセプタ・バインディング・タイプを複数のインターセプタ・クラスで使用するように定義できます。
インターセプタ・バインディング・タイプを定義するには:
例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クラスで発生するメソッド呼出しまたはライフ・サイクル・イベントへの割込みに使用されます。インターセプタ・クラスでは、ロギングや監査など、頻繁に実行されるが、アプリケーションのビジネス・ロジックからは分離されているタスクのコードを提供します。
インターセプタ・クラスを定義するには:
例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インターセプタは、インターセプタ・バインディングを使用して、インターセプタ・メソッドを特定し、インターセプトされるメソッドをそのインターセプタ・メソッドに関連付けます。インターセプトされるメソッドとインターセプタ・メソッドの両方に、バインディングで注釈付けする必要があります。このようにして、インターセプトされるメソッドとインターセプタ・メソッドは、インターセプタ・バインディングを介してのみ相互に関連付けされます。
例9-14 インターセプトのためのBeanクラスのすべてのメソッドの特定
この例では、@Transactional
インターセプタによって、インターセプトのためのShoppingCart
クラスのすべてのメソッドが特定されます。
package com.example.billpayment.interceptor; @Transactional public class ShoppingCart { ... }
例9-15 インターセプトのためのクラスの個別のメソッドの特定
この例では、@Transactional
インターセプタによって、インターセプトのためのShoppingCart
クラスのcheckout
メソッドのみが特定されます。
package com.example.billpayment.interceptor; public class ShoppingCart { ... @Transactional public void checkout() { ... } }
インターセプタの有効化
デフォルトでは、インターセプタは無効です。インターセプタを、メソッドの呼出しおよびイベントに割り込む必要がある場合は、インターセプタを明示的に有効化する必要があります。
インターセプタを有効化するには:
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> ...
プロデューサへのインターセプタの適用
CDI 1.xでは、インターセプタはプロデューサBeanにバインドされません。CDI 2.0では、インタフェースjavax.enterprise.inject.spi.InterceptionFactory<T>
が導入され、それにより、インターセプタをプロデューサ・メソッドの戻り値にプログラムで適用できるようになります。
InterceptionFactory
インタフェースを使用すると、メソッド呼出しがメソッド・インターセプタによってインターセプトされ、指定されたインスタンスに転送されるラッパー・インスタンスを作成できます。
publicinterfaceInterceptionFactory<T> {
InterceptionFactory<T> ignoreFinalMethods();
AnnotatedTypeConfigurator<T> configure();
T createInterceptedInstance(T instance);
}
BeanManager.createInterceptionFactory()
を呼び出して、InterceptionFactory
の実装を取得できます。次の例は、InterceptionFactory
を使用したプロデューサ・メソッドを示しています。
@Produces
@RequestScoped
public Product createInterceptedProduct(InterceptionFactory<Product> interceptionFactory) {
interceptionFactory.configure().add(ActionBinding.Literal.INSTANCE);
return interceptionFactory.createInterceptedInstance(new Product());
}
インターセプタの使用の詳細は、Java EE 8チュートリアルのCDIアプリケーションでのインターセプタの使用に関する項を参照してください。
マネージドBeanクラスの装飾
マネージドBeanクラスの装飾により、ビジネス・セマンティクスを持つ操作を実行する装飾されるクラスのメソッドの呼出しをインターセプトできます。
どのマネージドBeanクラスも装飾できます。
ノート:
デコレータ・クラスのプログラミング・モデルは、アプリケーションのビジネス・ロジックを実行する操作に対して最適化されています。アプリケーションのビジネス・ロジックから分離されているメソッドをインターセプトするには、「Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト」の説明に従ってインターセプタ・クラスを使用します
Java EE 8チュートリアルのデコレータの使用に関する項を参照してください。
マネージド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) { ... } }
親トピック: マネージドBeanクラスの装飾
デコレータ・クラスの有効化
デフォルトでは、デコレータ・クラスは無効です。CDIアプリケーションで、デコレータ・クラスを呼び出す必要がある場合は、デコレータ・クラスを明示的に有効化する必要があります。
デコレータ・クラスを有効化するには:
ノート:
アプリケーションに対して定義されているインターセプタ・クラスは、そのアプリケーションのデコレータ・クラスの前に呼び出されます。
beans.xml
ファイルの詳細は、「CDIアプリケーションの構成」を参照してください
例9-18は、デコレータ・クラスを有効化するためのbeans.xml
ファイルのclass
要素を示します。
例9-18 デコレータ・クラスの有効化
この例では、デコレータ・クラスcom.example.billpayment.decorator.DataAccessAuthDecorator
を有効化します。
... <decorators> <class>com.example.billpayment.decorator.DataAccessAuthDecorator</class> </decorators> ...
親トピック: マネージドBeanクラスの装飾
CDI BeanクラスへのEL名の割当て
ELにより、プレゼンテーション・レイヤーのコンポーネントが、アプリケーション・ロジックを実装するマネージドBeanと通信できます。
プレゼンテーション・レイヤーのコンポーネントは、通常、JavaServer Faces (JSF)ページおよびJavaServer Pages (JSP)ページです。『Oracle WebLogic Server Webアプリケーション、サーブレット、JSPの開発』のJSP式言語に関する項を参照してください。
JSPページおよびJSFページのスクリプト言語では、注入される変数の構文は、これらの言語の組込み変数の構文と同一です。JSPページまたはJSFページに注入されるCDI Beanは、EL名を介してアクセス可能であることが必要です。Java EE 8チュートリアルのBeanのEL名の指定に関する項を参照してください。
EL名をCDI Beanクラスに割り当てるには、javax.inject.Named
アノテーションでBeanクラスのクラス宣言に注釈付けします。
名前を指定しない場合、EL名は、最初の文字を小文字にした非修飾クラス名です。たとえば、非修飾クラス名がShoppingCart
である場合、EL名はshoppingCart
です。
名前を指定するには、@Named
アノテーションのvalue
要素を、目的の名前に設定します。
ノート:
EL名をCDI Beanクラスに割り当てるには、@Named
アノテーションでBeanクラス宣言に注釈付けする必要があります。クラスに@Named
で注釈付けされていない場合、CDI BeanクラスにEL名は付きません。
次の例は、@Named
アノテーションを使用してEL名をCDI Beanクラスに割り当てる方法を示します。この例では、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コンポーネントの構文に類似した構文を使用します。
次の例は、JSFページで、ShoppingCart
クラスのインスタンスに、そのクラスに割り当てられたEL名を介してアクセスする方法を示しています。
例9-19 EL名を介したBeanへのアクセス
この例では、ShoppingCart
クラスのインスタンスにアクセスし、JSFページにそのtotal
プロパティの値を表示します。
このプロパティは、ShoppingCart
クラスのgetTotal
getterメソッドによって返されます。
... <h:outputText value="#{cart.total}"/> ...
ステレオタイプの定義と適用
いくつかのBeanが類似した関数を実行する大規模なアプリケーションでは、場合によっては、同じアノテーションのセットをいくつかのBeanクラスに適用する必要があります。ステレオタイプを定義すると、アノテーションのセットの定義を一度行うのみで済みます。
その後、そのステレオタイプを使用して、同じアノテーションのセットを、それらのアノテーションを必要とするすべてのBeanクラスに適用できるようになります。Java EE 8チュートリアルのステレオタイプの使用に関する項を参照してください。
ステレオタイプの定義と適用には、次の項で説明するタスクが含まれます。
ステレオタイプの定義
ステレオタイプは、アプリケーション定義のアノテーション・タイプであり、他のアノテーション・タイプが組み込まれています。
ステレオタイプを定義するには:
次の例では、ステレオタイプの定義を示します。
例9-20 ステレオタイプの定義
この例では、ステレオタイプ@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には任意の数のステレオタイプを適用できます。Beanに適用するステレオタイプは、「ステレオタイプの定義」の説明に従って定義する必要があります
例9-21は、Beanにステレオタイプを適用する方法を示します。
例9-21 Beanへのステレオタイプの適用
この例では、ステレオタイプ@Action
および@Mock
をBeanクラスMockLoginAction
に適用します。@Action
ステレオタイプの定義を、例9-20に示します。@Mock
ステレオタイプの定義は、この例の範囲外です。
@Action @Mock public class MockLoginAction extends LoginAction { ... }
親トピック: ステレオタイプの定義と適用
Bean間の通信のためのイベントの使用方法
イベントを使用すると、Beanはコンパイル時の依存関係なしに情報を通信できます。
実行時に、アプリケーションで、情報を生成する処理が実行されたり、状態の変更が発生し、Bean間の通信が必要となる場合があります。たとえば、アプリケーションで、アプリケーションのアーキテクチャの1つの層のステートフルBeanがそれらの内部状態を、別の層で発生する状態の変更と同期することが必要な場合があります。
イベントを使用すると、Beanはコンパイル時の依存関係なしにこの情報を通信できます。1つのBeanでイベントを定義し、別のBeanでイベントを送信し、さらに別のBeanでそのイベントを処理できます。これらのBeanは、それぞれ別のパッケージに含めることができ、アプリケーションの別の層に含めることもできます。Java EE 8チュートリアルのイベントの使用に関する項を参照してください。
Bean間の通信のためのイベントの使用には、次の項で説明するタスクが含まれます。
イベント・タイプの定義
イベント・タイプは、Bean間で通信する情報を表すJavaクラスです。たとえば、イベント・タイプは、ステートフルBeanがアプリケーションの別の層における状態の変更と同期する必要がある状態情報を表す場合があります。
Bean間で通信する変更のセットごとにイベントのタイプを定義します。
イベント・タイプを定義するには:
親トピック: Bean間の通信のためのイベントの使用方法
イベントの送信
処理に応じて発生した変更を通信するには、アプリケーションが、処理を実行するときに正しいタイプのイベントを送信する必要があります。CDIは、実行時にアプリケーション・コードがイベントを送信し、関連付けられた修飾子を選択できるようにする事前定義済イベント・ディスパッチャ・オブジェクトを提供しています。
イベントを送信するには:
例9-22は、イベントを送信する方法を示します。
例9-22 イベントの送信
この例では、修飾子@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); } } ... }
親トピック: Bean間の通信のためのイベントの使用方法
イベントの処理
どのCDIマネージドBeanクラスもイベントを処理できます。
イベントを処理するには:
例9-23は、特定のタイプの修飾されたイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。例9-24は、特定のタイプのすべてのイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。
例9-23 特定のタイプの修飾されたイベントの処理
この例では、@Observes
アノテーションと@LoggedIn
修飾子でパラメータuser
が注釈付けされているafterLogin
メソッドを宣言します。このメソッドは、修飾子@LoggedIn
が付いたタイプUser
のイベントが送信されるときにコールされます。
import javax.enterprise.event.Observes; public void afterLogin(@Observes @LoggedIn User user) { ... }
例9-24 特定のタイプのイベントの処理
この例では、@Observes
アノテーションでパラメータuser
が注釈付けされているafterLogin
メソッドを宣言します。このメソッドは、タイプUser
のイベントが送信されるときにコールされます。
import javax.enterprise.event.Observes; public void afterLogin(@Observes User user) { ... }
親トピック: Bean間の通信のためのイベントの使用方法
事前定義済Beanの注入
事前定義済Beanは、Dependentスコープおよび事前定義済のデフォルト修飾子@Default
が指定されて注入されます。
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 8チュートリアルのリソースの注入に関する項を参照してください。
例9-25は、@Resource
アノテーションを使用して事前定義済Beanを注入する方法を示します。
例9-25 事前定義済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と同様にアプリケーションに注入できます。
プロデューサ・フィールドの詳細は、「プロデューサ・フィールドの定義」を参照してください
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; ... }
次の例は、CDIプロデューサ・フィールドと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に注入します。
次の例は、Java EEリソースをCDI Beanとして別の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
のインスタンスの作成 -
プロデューサ・フィールドを使用することによるエンティティ・マネージャ・ファクトリへの参照の注入
-
現在のリクエスト・コンテキストでの
SomeOtherClass
の新しいインスタンスの保存
どの場合も、CDIによって、SomeOtherClass
のこのインスタンスへの参照が、YetAnotherClass
のフィールドに注入されます。リクエスト・コンテキストが破棄されるときに、SomeOtherClass
のインスタンスおよびエンティティ・マネージャ・ファクトリへのその参照が破棄されます。
JCAテクノロジでのCDIの使用方法
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アプリケーションとして識別する必要があります。CDIマネージドBeanを定義するために、アノテーションなどの特別な宣言は必要ありません。CDIアプリケーションのパッケージ化のために特に定義されているモジュール・タイプはありません。
CDIアプリケーションを構成するには、beans.xml
という名前のファイルを、アプリケーションのパッケージ化されたアーカイブに含めます。beans.xml
ファイルは、eXtensible Markup Language (XML)スキーマbeans_2_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-26は、CDIアプリケーションを構成するためのbeans.xml
ファイルを示します。
例9-26 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://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.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を使用しない場合でも、WebLogic Serverでアプリケーションをデプロイする際に発生するCDIの初期化がいくつかあります。 CDIを使用しないアプリケーションのデプロイメント・パフォーマンスを最大化するために、CDIを無効にすることができます。
CDIコンテナでPolicy
パラメータを設定することにより、ドメイン内でCDIを有効にするかどうかを制御できます。このパラメータがEnabled
に設定されている場合、CDIはドメイン内のすべてのアプリケーションで有効です。Policy
パラメータがDisabled
に設定されている場合、CDIはドメイン内のすべてのアプリケーションで無効です。
1つのドメインに対してのみCDIを無効にすることができます。
1つのドメインに対するCDIの有効化および無効化
ドメインにデプロイされるすべてのアプリケーションに対してCDIを無効化するには、 config.xml
ファイルに次の行を追加します。
<domain>
<cdi-container>
<policy>Disabled</policy>
</cdi-container>
<domain>
WLSTスクリプト・ツールを使用してドメインに対するCDIを有効化または無効化できます。次の例は、WLSTを使用してオンラインまたはオフラインでドメインに対するCDIを有効化または無効化する方法を示します。
例9-27 オンライン時のCDIの有効化
次の例では、WebLogic Serverが稼働しています。引数usernameおよびpasswordは、サーバーにWLSTを接続しているユーザーの資格証明を表し、urlは、サーバー・インスタンスのリスニング・アドレスおよびリスニング・ポートを表します(たとえば、localhost:7001)。また、domainはドメイン名を表す必要があります。
connect('user','password','url')
domainConfig()
edit()
cd('CdiContainer/mydomain')
startEdit()
set('Policy','Enabled') // 'Enabled' or 'Disabled'
validate()
save()
activate(block="true")
例9-28 オフライン時のCDIの有効化
次の例では、domainはドメインのパスを表します(たとえば、/oracle/wls/
mydomain)。また、mydomain
はドメイン名と一致する必要があります。
readDomain('domain')
create('mydomain','CdiContainer')
cd('CdiContainer/mydomain')
set('Policy','Enabled') // 'Enabled' or 'Disabled'
updateDomain()
closeDomain()
親トピック: CDIの有効化および無効化
暗黙的Beanの検出
CDI 1.1およびJava EE 7では、暗黙的Beanアーカイブの概念を導入しました。暗黙的Beanアーカイブは、beans.xml
ファイルを持たないJARファイルまたはWARファイルのアーカイブです。CDIによって管理できるBeanを持ちます。
これは、アプリケーションをデプロイするのにかかる時間を大幅に増やす可能性があります。この時間の増加は、Java EE 7より前のリリース用に作成され、Java EE 7アプリケーション・サーバーにデプロイされたアプリケーションで特に顕著です。CDI 1.0との互換性を持つために、WebLogic Serverにはbeans.xml
ファイルがない場合でもコンテナでアーカイブを無視するように設定するオプションが含まれています。
CDIコンテナでimplicit-bean-discovery-enabled
パラメータを設定して、暗黙的Beanの検出が有効かどうかをドメインで制御します。このパラメータが1
に設定されている場合、暗黙的Beanの検出はドメイン内のすべてのアプリケーションで有効化されます。implicit-bean-discovery-enabled
パラメータが0
に設定されている場合、暗黙的Beanの検出はドメイン内のすべてのアプリケーションに対して無効です。
1つのドメインに対してのみ暗黙的Beanの検出を無効にできます。
1つのドメインに対する暗黙的Beanの検出の有効化および無効化
ドメインにデプロイされるすべてのアプリケーションに対して暗黙的Beanの検出を無効化するには、config.xml
ファイルに次の行を追加します。
<domain>
<cdi-container>
<implicit-bean-discovery-enabled>false</implicit-bean-discobery-enabled>
</cdi-container>
<domain>
WLSTスクリプト・ツールを使用してこの機能を有効化または無効化できます。次の例は、WLSTを使用してオンラインまたはオフラインでドメインに対する暗黙的Beanの検出を有効化または無効化する方法を示します。
例9-29 WLSTをオンラインで使用した暗黙的Beanの検出の有効化
次の例では、WebLogic Serverが稼働しています。引数usernameおよびpasswordは、サーバーにWLSTを接続しているユーザーの資格証明を表し、urlは、サーバー・インスタンスのリスニング・アドレスおよびリスニング・ポートを表します(たとえば、localhost:7001)。また、domainはドメイン名を表す必要があります。
connect('user','password','url') domainConfig() edit() cd('CdiContainer/mydomain') startEdit() set('ImplicitBeanDiscoveryEnabled',1) // 1 to enable 0 to disable validate() save() activate(block="true")
例9-30 WLSTをオフラインで使用した暗黙的Beanの検出の有効化
次の例では、domainはドメインのパスを表します(たとえば、/oracle/wls/
mydomain)。また、mydomain
はドメイン名と一致する必要があります。
readDomain(domain)
create('mydomain','CdiContainer')
cd('CdiContainer/mydomain')
set('ImplicitBeanDiscoveryEnabled',1)
// 1 to enable 0 to disable
updateDomain()
closeDomain()
親トピック: 暗黙的Beanの検出
サード・パーティのポータブルな拡張のサポート
CDIは、フレームワーク、拡張、および他のテクノロジとの統合の基盤となることを目的としています。
CDIは、次のようなCDIへのポータブルな拡張の開発を可能にするSPIを公開しています。
-
ビジネス・プロセス管理エンジンとの統合
-
Spring、Seam、GWT、Wicketなどサード・パーティのフレームワークとの統合
-
CDIプログラミング・モデルに基づいた新しいテクノロジ
CDIへのポータブルな拡張の開発を可能にするSPIは、javax.enterprise.inject.spi
パッケージで提供されています。
CDIの拡張のコードは、CDIフレームワークによって送信されるイベントを処理できます。
詳細は、JSR 365: Contexts and Dependency Injection for the Java EE platformのPortable extensionsを参照してください。
組込みアノテーション・リテラルの使用
CDI 2.0では、アノテーションのインスタンスの作成に使用できる新しい組込みアノテーション・リテラルが導入されています。
構文
次に、Literal
静的ネスト・クラスを定義する新しい組込みアノテーションを示します。
表9-2 組込みアノテーション・リテラル
クラス | パッケージ |
---|---|
Any |
javax.enterprise.inject |
Default |
javax.enterprise.inject |
New |
javax.enterprise.inject |
Specialized |
javax.enterprise.inject |
Veteod |
javax.enterprise.inject |
Alternative |
javax.enterprise.inject |
Typed |
javax.enterprise.inject |
Nonbinding |
javax.enterprise.util |
Initialized |
javax.enterprise.context |
Destroyed |
javax.enterprise.context |
RequestScoped |
javax.enterprise.context |
SessionScoped |
javax.enterprise.context |
ApplicationScoped |
javax.enterprise.context |
Dependent |
javax.enterprise.context |
ConversationScoped |
javax.enterprise.context |
例9-31 組込みアノテーション・リテラル
Default defaultLiteral = new Default.Literal();
コンフィギュレータ・インタフェースの使用
CDI 2.0では、CDIオブジェクトを動的に定義または変更するために使用できる、新しいコンフィギュレータ・インタフェースがいくつか導入されました。
新しく導入されたコンフィギュレータ・インタフェースは次のとおりです。
AnnotatedTyeConfigurator
InjectionPointConfigurator
BeanAttributesConfigurator
BeanConfigurator
ObserverMethodConfigurator
ProducerConfigurator
詳細は、Java EE 8チュートリアルのコンフィギュレータ・インタフェースの使用に関する項を参照してください。
CDIコンテナのブートストラップ
CDI 2.0では、Java SEのCDIコンテナをブートストラップするための標準APIが提供されます。SeContainerInitializer
抽象クラスとその静的メソッドnewInstance()
を使用して、CDIコンテナを明示的にブートストラップする必要があります。
ブートストラップされる前にAPI javax.enterprise.inject.se.SeContainerInitializer
を使用してCDIコンテナを構成し、SeContainerInitializer.initialize()
メソッドによってコンテナがブートストラップされ、SeContainer
インスタンスが返されます。
詳細は、Java EE 8チュートリアルのCDIコンテナの構成に関する項を参照してください。