7.4. 管理 Bean

Java EE では管理対象 Bean 仕様の共通定義が確立されています。管理対象 bean は、プログラミングの制限が最小限であるコンテナー管理オブジェクトとして定義され、POJO (Plain Old Java Object) として知られるようになりました。管理対象 bean はリソースのインジェクション、ライフサイクルコールバック、インターセプターなどの基本サービスの小さなセットをサポートします。EJBや CDI などのコンパニオン仕様は、この基本モデルに基づいて構築されます。

ごくわずかな例外を除き、パラメーターのないコンストラクター (または @Inject アノテーションが指定されたコンストラクター) を持つ具象 Java クラスは bean になります。これには、すべての Java Bean と EJB セッション bean が含まれます。

7.4.1. Bean であるクラスのタイプ

管理対象 bean は Java クラスです。管理対象 bean の基本的なライフサイクルやセマンティクスは、管理対象 Bean の仕様で定義されています。bean クラス @ManagedBean アノテーションを付けることで明示的に管理対象 bean を宣言できますが、CDI ではその必要はありません。この仕様によると、CDI コンテナーでは、以下の条件を満たすクラスはすべて管理対象 bean として扱われます。

  • 非静的な内部クラスではないこと。
  • 具象クラス、あるいは @Decorator アノテーションが付与されている。
  • EJB コンポーネントを定義するアノテーションが付与されていないこと、あるいは ejb-jar.xml ファイルで EJB bean クラスとして宣言されていること。
  • インターフェース javax.enterprise.inject.spi.Extension を実装しないこと。
  • パラメーターのないコンストラクターか、@Inject アノテーションが付与されたコンストラクターがあること。
  • @Vetoed アノテーションが付いていないこと、または @Vetoed アノテーションが付けられたパッケージ内にないこと。

管理対象 bean の無制限の bean 型には、直接的あるいは間接的に実装する bean クラス、スーパークラスすべて、およびインターフェースすべてが含まれます。

管理対象 Bean にパブリックフィールドがある場合は、デフォルトの @Dependent スコープが必要です。

@Vetoed

@Vetoed アノテーションは CDI 1.1 で導入されました。このアノテーションを追加することにより、Bean をインジェクションから除外できます。

@Vetoed
public class SimpleGreeting implements Greeting {
    ...
}

このコードでは、SimpleGreeting Bean はインジェクションの対象となりません。

パッケージ内のすべての bean をインジェクションから除外できます。

@Vetoed
package org.sample.beans;

import javax.enterprise.inject.Vetoed;

org.sample.beans パッケージ内の package-info.java のこのコードにより、このパッケージ内のすべての Bean がインジェクションから除外されます。

ステートレス EJB や JAX-RS リソースエンドポイントなどの Java EE コンポーネントには、bean と見なされないように @Vetoed を付けることができます。@Vetoed アノテーションをすべての永続エンティティーに追加すると、BeanManager がエンティティーを CDI Bean として管理しないようになります。エンティティーに @Vetoed アノテーションが付けられた場合は、インジェクションが行われません。これは、JPA プロバイダーの破損原因となる操作を BeanManager が実行しないようにするためです。

7.4.2. CDI を用いたオブジェクトの Bean へのインジェクト

CDI コンポーネントがアプリケーションで検出されると、CDI は自動的にアクティベートされます。デフォルト値と異なるよう設定をカスタマイズする場合は、デプロイメントアーカイブに META-INF/beans.xml ファイルまたは WEB-INF/beans.xml ファイルを含めることができます。

他のオブジェクトにオブジェクトをインジェクトする
  1. クラスのインスタンスを取得するには、bean 内でフィールドに @Inject アノテーションを付けます。

    public class TranslateController {
       @Inject TextTranslator textTranslator;
       ...
  2. インジェクトしたオブジェクトのメソッドを直接使用します。TextTranslator にメソッド translate があることを前提とします。

    // in TranslateController class
    
    public void translate() {
       translation = textTranslator.translate(inputText);
    }
  3. Bean のコンストラクターでインジェクションを使用します。ファクトリーやサービスロケーターを使用して作成する代わりに、Bean のコンストラクターへオブジェクトをインジェクトできます。

    public class TextTranslator {
    
       private SentenceParser sentenceParser;
       private Translator sentenceTranslator;
    
       @Inject
       TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
          this.sentenceParser = sentenceParser;
          this.sentenceTranslator = sentenceTranslator;
       }
    
       // Methods of the TextTranslator class
       ...
    }
  4. Instance(<T>) インターフェースを使用してインスタンスをプログラムにより取得します。Bean 型でパラメーター化されると、Instance インターフェースは TextTranslator のインスタンスを返すことができます。

    @Inject Instance<TextTranslator> textTranslatorInstance;
    ...
    public void translate() {
       textTranslatorInstance.get().translate(inputText);
    }

オブジェクトを Bean にインジェクトすると、Bean は全オブジェクトのメソッドとプロパティーを使用できるようになります。Bean のコンストラクターにインジェクトするときに、インジェクションがすでに存在するインスタンスを参照する場合以外は、Bean のコンストラクターが呼び出されるとインジェクトされたオブジェクトのインスタンスが作成されます。たとえば、セッションの存続期間内にセッションスコープの Bean をインジェクトしても、新しいインスタンスは作成されません。