プライマリ・コンテンツに移動
Oracle® Fusion Middleware Oracle WebLogic Server 12.1.3アプリケーションの開発
12c (12.1.3)
E57574-04
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次

前
 
次
 

9 Contexts and Dependency Injection for the Java EE Platformの使用方法

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 for the Java EE Platformについて

CDIは、『Java Specification Request (JSR) 299: Contexts and Dependency Injection for the Java EE platform』によって指定されています。この仕様は、以前はWeb Beansと呼ばれていました。CDIは、次の関連する仕様を使用します。

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の定義

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の注入

自身で定義する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に注入する方法を示します。

例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 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のスコープのオーバーライド

注入ポイントでの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タイプの実装に対する修飾子の定義

修飾子は、アプリケーションによって定義されるアノテーションであり、Beanタイプの実装の識別を可能にします。提供するBeanタイプの実装ごとに修飾子を1つ定義します。

修飾子は、Beanタイプの複数の実装を提供し、かつ代替を使用していない場合にのみ定義します。Beanタイプに対して修飾子が定義されていない場合、そのタイプのBeanが注入されるときにCDIによって事前定義済修飾子@Defaultが適用されます。


注意:

CDIでは、修飾子が特定のBeanに一意である必要はありません。1つの修飾子を複数のBeanタイプに定義できます。

修飾子を定義する手順は、次のとおりです。

  1. その修飾子を表すJavaアノテーション・タイプを定義します。

  2. javax.inject.Qualifierアノテーションでアノテーション・タイプの宣言に注釈付けします。

  3. 実行時に仮想マシンによってその修飾子が保持されることを指定します。

    このためには、java.lang.annotation.Retention(RUNTIME)メタアノテーションを使用します。

  4. その修飾子をプログラム要素METHODFIELDPARAMETERおよび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に修飾子を適用すると、Beanタイプの実装が特定されます。1つのBeanに、任意の数の修飾子を適用することも、修飾子を適用しないこともできます。Beanに修飾子が適用されていない場合、CDIによって暗黙的に事前定義済修飾子@DefaultがそのBeanに適用されます。


注意:

CDIでは、修飾子が特定のBeanに一意である必要はありません。1つのアプリケーション内で使用可能な一連のBeanで異なるタイプのBeanに同じ修飾子を適用できます。

修飾子をBeanに適用するには、そのBeanのクラス宣言に、適用する各修飾子で注釈付けします。Beanに適用する修飾子は、「Beanタイプの実装に対する修飾子の定義」の説明に従って定義する必要があります。

次の例では、修飾子@BeanCounterおよび@PeopleManagerManager 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例9-5に示しています。

  • Boss例9-6に示しています。

この例では、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 6チュートリアル代替の使用方法に関する項を参照してください。


注意:

開発時に複数の代替の実装から選択するには、「修飾子の使用方法」の説明に従って修飾子を使用します。

Beanタイプの代替の実装の提供には、次の項で説明するタスクが含まれます。

Beanタイプの代替の実装の定義

Beanタイプの代替の実装を定義する手順は、次のとおりです。

  1. Beanタイプのプライマリの実装と同じBeanタイプのBeanクラスを作成します。

    どの代替もアプリケーションに注入できるようにするには、すべての代替とプライマリの実装が、すべて同じBeanタイプであることが必要です。Beanの注入方法の詳細は、「Beanの注入」を参照してください。

  2. 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 {
 ...
}

アプリケーションに対するBeanタイプの代替の実装の選択

デフォルトでは、CDIはアプリケーションへの注入にBeanタイプのプライマリの実装を選択します。代替の実装を注入する必要がある場合は、明示的にその代替を選択する必要があります。

アプリケーションに対して代替の実装を選択する手順は、次のとおりです。

  1. beans.xmlファイルのalternatives要素に、代替のclass要素を追加します。

  2. 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へのスコープと修飾子の適用

CDIでは、スコープおよび修飾子をセッションBeanに適用できます。セッションBeanは、次の要件のいずれかを満たすEJBコンポーネントです。

  • Beanを実装するクラスには、次のいずれかのアノテーションが付いています。

  • そのBeanが、ejb-jar.xmlデプロイメント記述子ファイルにリストされています。

セッションBeanの詳細は、次のドキュメントを参照してください。

  • Oracle WebLogic Server Enterprise JavaBeansの開発

  • Oracle WebLogic Server Enterprise JavaBeansバージョン2.1の開発

セッションBeanへのスコープの適用

CDIによりセッションBeanに適用できるスコープは、表9-1に示すようにセッションBeanのタイプに応じて異なります。

表9-1 セッションBeanに適用できるCDIスコープ

セッションBeanタイプ 適用できるスコープ

シングルトン

次のスコープのいずれかです。

  • Dependent

  • Application

ステートフル

任意

ステートレス

Dependent


CDIにおけるスコープの詳細は、「Beanのスコープの定義」を参照してください。

CDIで、ステートフル・セッションBeanへの参照が注入されるときは、CDIによってBeanが作成され、Beanのフィールドが注入され、そのスコープに応じてステートフル・セッションBeanが管理されます。コンテキストを破棄するときは、CDIによってステートフル・セッションBeanの削除メソッドがコールされ、その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は起動しません。

プロデューサ・フィールドには、ディスポーザはありません。

マネージドBeanの初期化と破棄の準備

CDIマネージドBeanクラスおよびそれらのスーパークラスでは、マネージドBeanの初期化と破棄の準備のためのアノテーションがサポートされています。これらのアノテーションは、『JSR 250: Common Annotations for the Java Platform』で定義されています。詳細は、第8章「Java EEアノテーションと依存関係インジェクションの使用」を参照してください。

マネージドBeanの初期化

マネージドBeanの初期化では、依存関係インジェクションの後、クラスがサービスを開始する前にCDIフレームワークがコールする必要があるライフ・サイクル・コールバック・メソッドを指定します。

マネージドBeanを初期化する手順は、次のとおりです。

  1. マネージドBeanクラスまたはそのスーパークラスのいずれかで、必要な初期化を実行するメソッドを定義します。

  2. javax.annotation.PostConstructアノテーションで、メソッドの宣言に注釈付けします。

    マネージドBeanがコンポーネントに注入されると、すべての注入が実行され、すべてのイニシャライザがコールされた後にCDIによってそのメソッドがコールされます。


    注意:

    JSR 250で規定されているように、注釈付けされたメソッドがスーパークラスで宣言される場合、宣言するクラスのサブクラスがそのメソッドをオーバーライドしないかぎり、そのメソッドがコールされます。

マネージドBeanの破棄の準備

マネージドBeanの破棄の準備では、アプリケーション・コンポーネントがコンテナによって破棄されようとしていることを通知するライフ・サイクル・コールバック・メソッドを指定します。

マネージドBeanの破棄を準備する手順は、次のとおりです。

  1. マネージドBeanクラスまたはそのスーパークラスのいずれかで、マネージドBeanの破棄を準備するメソッドを定義します。

    このメソッドでは、Beanが保持していたリソースの解放など、Beanを破棄する前に必要なクリーンアップを実行します。

  2. javax.annotation.PreDestroyアノテーションで、メソッドの宣言に注釈付けします。

    Beanを破棄するためのロジックを開始する前にCDIによってそのメソッドがコールされます。


    注意:

    JSR 250で規定されているように、注釈付けされたメソッドがスーパークラスで宣言される場合、宣言するクラスのサブクラスがそのメソッドをオーバーライドしないかぎり、そのメソッドがコールされます。

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 6チュートリアルインターセプタの使用方法に関する項を参照してください。

Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプトには、次の項で説明するタスクが含まれます。

インターセプタ・バインディング・タイプの定義

インターセプタ・バインディング・タイプは、インターセプタ・クラスとインターセプトされるBeanを関連付けるアプリケーション定義のアノテーションです。必要なインターセプタのタイプごとにインターセプタ・バインディング・タイプを定義します。


注意:

CDIでは、インターセプタ・バインディング・タイプが特定のインターセプタ・クラスに固有でなくても構いません。1つのインターセプタ・バインディング・タイプを複数のインターセプタ・クラスで使用するように定義できます。

インターセプタ・バインディング・タイプを定義する手順は、次のとおりです。

  1. インターセプタ・バインディング・タイプを表すJavaアノテーション・タイプを定義します。

  2. javax.interceptor.InterceptorBindingアノテーションで、アノテーション・タイプの宣言に注釈付けします。

  3. インターセプタ・バインディング・タイプが、実行時に仮想マシンによって保持されることを指定します。

    このためには、java.lang.annotation.Retention(RUNTIME)メタアノテーションを使用します。

  4. インターセプタ・バインディング・タイプを、プログラム要素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クラスで発生するメソッド呼出しまたはライフ・サイクル・イベントへの割込みに使用されます。インターセプタ・クラスでは、ロギングや監査など、頻繁に実行されるが、アプリケーションのビジネス・ロジックからは分離されているタスクのコードを提供します。

インターセプタ・クラスを定義する手順は、次のとおりです。

  1. インターセプタを表すJavaクラスを定義します。

  2. 次のアノテーションでクラス宣言に注釈付けします。

    • javax.interceptor.Interceptor

    • クラスに対して定義されているインターセプタ・バインディング・タイプ

      1つのインターセプタ・クラスに、任意の数のインターセプタ・バインディング・タイプを適用できます。


      注意:

      CDIでは、インターセプタ・バインディング・タイプが特定のインターセプタ・クラスに固有でなくても構いません。同じインターセプタ・バインディング・タイプを複数のインターセプタ・クラスに適用できます。

  3. そのクラス内にインターセプタ・メソッドを実装します。

    CDIでは、インターセプタ・メソッドのシグネチャがインターセプトされるメソッドのシグネチャに一致する必要はありません。

  4. クラス内のインターセプタ・メソッドを特定します。

    インターセプタ・メソッドは、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インターセプタは、インターセプタ・バインディングを使用して、インターセプタ・メソッドを特定し、インターセプトされるメソッドをそのインターセプタ・メソッドに関連付けます。インターセプトされるメソッドとインターセプタ・メソッドの両方に、バインディングで注釈付けする必要があります。このようにして、インターセプトされるメソッドとインターセプタ・メソッドは、インターセプタ・バインディングを介してのみ相互に関連付けされます。

例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() {
    ...
    }
}

インターセプタの有効化

デフォルトでは、インターセプタは無効です。インターセプタを、メソッドの呼出しおよびイベントに割り込む必要がある場合は、インターセプタを明示的に有効化する必要があります。

インターセプタを有効化する手順は、次のとおりです。

  1. beans.xmlファイルのinterceptors要素にインターセプタのclass要素を追加します。

  2. 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クラスも装飾できます。


注意:

デコレータ・クラスのプログラミング・モデルは、アプリケーションのビジネス・ロジックを実行する操作に対して最適化されています。アプリケーションのビジネス・ロジックから分離されているメソッドをインターセプトするには、「Beanクラスのメソッド呼出しおよびライフ・サイクル・イベントのインターセプト」の説明に従ってインターセプタ・クラスを使用します。

詳細は、Java EE 6チュートリアルデコレータの使用方法に関する項を参照してください。

マネージドBeanクラスの装飾には、次の項で説明するタスクが含まれます。

デコレータ・クラスの定義

デコレータ・クラスは、ビジネス・セマンティクスを持つ操作を実行する装飾されるクラスのメソッドの呼出しをインターセプトします。デコレータ・クラスおよびインターセプタ・クラスは類似しており、どちらもメソッド周辺のインターセプトを提供します。ただし、デコレータ・クラスのメソッドは、装飾されるBeanクラスのインターセプトされるメソッドと同じシグネチャを持ちます。

デコレータ・クラスを定義する手順は、次のとおりです。

  1. 装飾対象のBeanクラスと同じインタフェースを実装するJavaクラスを作成します。

    装飾されるクラスのいくつかのメソッドのみをインターセプトする場合は、デコレータ・クラスを抽象クラスとして宣言します。クラスを抽象として宣言する場合、装飾対象のBeanクラスのすべてのメソッドを実装する必要はありません。

  2. javax.decorator.Decoratorアノテーションでデコレータ・クラスのクラス宣言に注釈付けします。

  3. インターセプトする装飾されるBeanクラスのメソッドを実装します。

    デコレータ・クラスが具体クラスである場合、装飾するBeanクラスのすべてのメソッドを実装する必要があります。

    デコレータ・クラスのインターセプトするメソッドが、装飾されるBeanクラスのインターセプトされるメソッドと同じシグネチャを持つようにしてください。

  4. デコレータ・クラスに委任注入ポイントを追加します。

    デコレータ・クラスには、委任注入ポイントが1つのみ含まれている必要があります。委任注入ポイントは、装飾されるクラスのインスタンスである委任オブジェクトを、デコレータ・オブジェクトに注入します。

    デコレータ・オブジェクトのメソッドが、装飾されるメソッドの実装を処理する方法をカスタマイズできます。CDIでは、デコレータ・オブジェクトが、対応する委任オブジェクトを呼び出すことができますが、これは必須ではありません。したがって、デコレータ・オブジェクトに、対応する委任オブジェクトを呼び出させるかどうかは自由に選択できます。

    1. デコレータ・クラスで、装飾するBeanクラスのインスタンスを注入します。

    2. javax.decorator.Delegateアノテーションで、注入ポイントに注釈付けします。

    3. 注入ポイントに修飾子を適用する必要がある場合は、適用します。

      注入ポイントに修飾子を適用すると、デコレータは、注入ポイントの修飾子に一致する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アプリケーションで、デコレータ・クラスを呼び出す必要がある場合は、デコレータ・クラスを明示的に有効化する必要があります。

デコレータ・クラスを有効化する手順は、次のとおりです。

  1. beans.xmlファイルのdecorators要素に、デコレータ・クラスのclass要素を追加します。

  2. class要素に、そのデコレータ・クラスの完全修飾クラス名を指定します。

    beans.xmlファイル内のclass要素の順序が、デコレータ・クラスの呼出し順序と一致するようにします。


注意:

アプリケーションに対して定義されているインターセプタ・クラスは、そのアプリケーションのデコレータ・クラスの前に呼び出されます。

beans.xmlファイルの詳細は、「CDIアプリケーションの構成」を参照してください。

例9-18は、デコレータ・クラスを有効化するためのbeans.xmlファイルのclass要素を示します。

例9-18 デコレータ・クラスの有効化

この例では、デコレータ・クラスcom.example.billpayment.decorator.DataAccessAuthDecoratorを有効化します。

...
<decorators>
     <class>com.example.billpayment.decorator.DataAccessAuthDecorator</class>
</decorators>
...

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 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名cartShoppingCartクラスに割り当てます。

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チュートリアルステレオタイプの使用方法に関する項を参照してください。

ステレオタイプの定義と適用には、次の項で説明するタスクが含まれます。

ステレオタイプの定義

ステレオタイプは、アプリケーション定義のアノテーション・タイプであり、他のアノテーション・タイプが組み込まれています。

ステレオタイプを定義する手順は、次のとおりです。

  1. ステレオタイプを表すJavaアノテーション・タイプを定義します。

  2. 次のアノテーションでアノテーション・タイプの宣言に注釈付けします。

  3. ステレオタイプが、実行時に仮想マシンによって保持されることを指定します。

    このためには、java.lang.annotation.Retention(RUNTIME)メタアノテーションを使用します。

  4. ステレオタイプをプログラム要素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には任意の数のステレオタイプを適用できます。Beanに適用するステレオタイプは、「ステレオタイプの定義」の説明に従って定義する必要があります。

例9-22は、Beanにステレオタイプを適用する方法を示します。

例9-22 Beanへのステレオタイプの適用

この例では、ステレオタイプ@Actionおよび@MockをBeanクラスMockLoginActionに適用します。@Actionステレオタイプの定義を、例9-21に示します。@Mockステレオタイプの定義は、この例の範囲外です。

@Action
@Mock
public class MockLoginAction extends LoginAction {
 ... 
}

Bean間の通信のためのイベントの使用方法

実行時に、アプリケーションで、情報を生成する処理が実行されたり、状態の変更が発生し、Bean間の通信が必要となる場合があります。たとえば、アプリケーションで、アプリケーションのアーキテクチャの1つの層のステートフルBeanがそれらの内部状態を、別の層で発生する状態の変更と同期することが必要な場合があります。

イベントを使用すると、Beanはコンパイル時の依存関係なしにこの情報を通信できます。1つのBeanでイベントを定義し、別のBeanでイベントを送信し、さらに別のBeanでそのイベントを処理できます。これらのBeanは、それぞれ別のパッケージに含めることができ、アプリケーションの別の層に含めることもできます。詳細は、Java EE 6チュートリアルイベントの使用方法に関する項を参照してください。

Bean間の通信のためのイベントの使用には、次の項で説明するタスクが含まれます。

イベント・タイプの定義

イベント・タイプは、Bean間で通信する情報を表すJavaクラスです。たとえば、イベント・タイプは、ステートフルBeanがアプリケーションの別の層における状態の変更と同期する必要がある状態情報を表す場合があります。

Bean間で通信する変更のセットごとにイベントのタイプを定義します。

イベント・タイプを定義する手順は、次のとおりです。

  1. そのイベント・タイプを表すJavaクラスを定義します。

    そのクラスが、次の要件を満たすようにします。

    • クラスが具体Javaクラスとして宣言されています。

    • クラスにタイプ変数がありません。

      イベントのイベント・タイプには、イベント・オブジェクトのランタイム・クラスのすべてのスーパークラスとインタフェースが含まれます。イベント・タイプには、タイプ変数を含めないでください。どのJavaタイプも監視対象のイベント・タイプにできます。

  2. 必要であれば、このタイプのイベントをさらに区別するための修飾子を定義します。詳細は、「Beanタイプの実装に対する修飾子の定義」を参照してください。

  3. クラスにコードを指定して、クラスからインスタンス化されるイベント・オブジェクトのイベント・ペイロードを移入します。

    イベント・ペイロードとは、そのイベントに含める情報です。getterおよびsetterメソッドとともにJavaBeansプロパティを使用して、イベント・ペイロード内の情報のアイテムを表すことができます。

イベントの送信

処理に応じて発生した変更を通信するには、アプリケーションが、処理を実行するときに正しいタイプのイベントを送信する必要があります。CDIは、実行時にアプリケーション・コードがイベントを送信し、関連付けられた修飾子を選択できるようにする事前定義済イベント・ディスパッチャ・オブジェクトを提供しています。

イベントを送信する手順は、次のとおりです。

  1. 送信するイベント・タイプのインスタンスを取得します。

  2. 送信するイベント・オブジェクトのイベント・ペイロードを移入するためのイベント・インスタンスのメソッドをコールします。

  3. パラメータ化javax.enterprise.event.Eventインタフェースのインスタンスを注入します。

    修飾イベントを送信する場合、イベント修飾子で注入ポイントに注釈付けします。

  4. 注入される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クラスもイベントを処理できます。

イベントを処理する手順は、次のとおりです。

  1. Beanクラスでは、イベントを処理するメソッドを定義します。


    注意:

    修飾子をイベント・タイプに適用する場合、修飾されるタイプごとに1つのメソッドを定義します。

  2. メソッドのシグネチャで、メソッドにイベントを渡すためのパラメータを定義します。

    パラメータのタイプは、必ずイベントのJavaタイプと同一になるようにします。

  3. javax.enterprise.event.Observesアノテーションで、メソッド・シグネチャのパラメータに注釈付けします。

    必要であれば、メソッドが条件付であるかトランザクションであるかを指定する@Observesアノテーションの要素を設定します。詳細は、Java EE 6チュートリアルオブザーバ・メソッドを使用したイベントの処理に関する項を参照してください。

  4. イベント・タイプが修飾されている場合は、注釈付けされるパラメータに修飾子を適用します。

  5. メソッド本体に、イベント・オブジェクトのイベント・ペイロードを処理するためのコードを指定します。

例9-24は、特定のタイプの修飾されたイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。例9-25は、特定のタイプのすべてのイベントを受信するためのオブザーバ・メソッドを宣言する方法を示します。

例9-24 特定のタイプの修飾されたイベントの処理

この例では、@Observesアノテーションと@LoggedIn修飾子でパラメータuserが注釈付けされているafterLoginメソッドを宣言します。このメソッドは、修飾子@LoggedInが付いたタイプUserのイベントが送信されるときにコールされます。

import javax.enterprise.event.Observes;

    public void afterLogin(@Observes @LoggedIn User user) {
        ...
    }

例9-25 特定のタイプのイベントの処理

この例では、@Observesアノテーションでパラメータuserが注釈付けされているafterLoginメソッドを宣言します。このメソッドは、タイプUserのイベントが送信されるときにコールされます。

import javax.enterprise.event.Observes;

    public void afterLogin(@Observes User user) {
        ...
    }

事前定義済Beanの注入

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. アプリケーション内の1箇所のみで、Java EE 5のリソース注入を使用します。

  2. プロデューサ・フィールドを使用して、注入されるリソース・タイプを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によって次の一連の処理が実行されます。

  1. SomeOtherClassのインスタンスの作成

  2. 例9-28のプロデューサ・フィールドを使用することによるエンティティ・マネージャ・ファクトリへの参照の注入

  3. 現在のリクエスト・コンテキストでの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_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」を参照してください。