7.2. CDI を使用したアプリケーションの開発

コンテキストと依存関係の注入 (CDI: Contexts and Dependency Injection) を使用すると、アプリケーションの開発、コードの再利用、デプロイメント時または実行時のコードの調整、およびユニットテストを非常に柔軟に行うことができます。JBoss EAP には、CDI の参照実装である Weld が含まれます。これらのタスクは、エンタープライズアプリケーションで CDI を使用する方法を示しています。

Weld にはアプリケーション開発の特別なモードが含まれています。開発モードを有効にすると、CDI アプリケーションの開発を容易にする一部のビルドインツールが利用できます。

注記

アプリケーションのパフォーマンスに悪影響を与えるため、開発モードは本番環境では使用しないでください。必ずデプロイメントモードを無効にしてから本番環境にデプロイしてください。

Web アプリケーションに対して開発モードを有効にするには、以下を行います。

Web アプリケーションの場合、サーブレット初期化パラメーター org.jboss.weld.developmenttrue に設定します。

<web-app>
    <context-param>
        <param-name>org.jboss.weld.development</param-name>
        <param-value>true</param-value>
    </context-param>
</web-app>

管理 CLI を使用して JBoss EAP に対して開発モードを有効にするには、以下を行います。

development-mode 属性を true に設定すると、デプロイされたアプリケーションすべてに対して Weld 開発モードをグローバルに有効にすることが可能です。

/subsystem=weld:write-attribute(name=development-mode,value=true)

7.2.1. デフォルトの Bean 検出モード

bean アーカイブのデフォルトの bean 検出モードは annotated です。このような bean アーカイブは implicit bean archive と呼ばれます。

bean 検出モードが annotated の場合:

  • bean defining annotation がなく、セッション bean の bean クラスでない bean クラスが検出されません。
  • セッション bean 上になく、bean クラスが bean 定義アノテーションを持たないプロデューサーメソッドが検出されません。
  • セッション bean 上になく、bean クラスが bean 定義アノテーションを持たないプロデューサーフィールドが検出されません。
  • セッション bean 上になく、bean クラスが bean 定義アノテーションを持たないディスポーザーメソッドが検出されません。
  • セッション bean 上になく、bean クラスが bean 定義アノテーションを持たないオブザーバーメソッドが検出されません。
重要

CDI セクションのすべての例は、検出モードが all に設定された場合にのみ有効です。

bean 定義アノテーション

bean クラスは bean defining annotation を持つことがあり、bean アーカイブで定義されたようにアプリケーションのどこにでも配置することができます。bean 定義アノテーションを持つ bean クラスは暗黙的な bean と呼ばれます。

bean 定義アノテーションのセットには以下のものが含まれます。

  • @ApplicationScoped@SessionScoped@ConversationScoped および @RequestScoped アノテーション
  • その他すべての通常スコープタイプ。
  • @Interceptor および @Decorator アノテーション。
  • @Stereotype 付けられたアノテーションなど、stereotype アノテーションすべて。
  • @Dependent スコープアノテーション。

これらのアノテーションのいずれかが bean クラスで宣言された場合、その bean クラスは bean 定義アノテーションを持っていることになります。

例: bean 定義アノテーション

@Dependent
public class BookShop
        extends Business
        implements Shop<Book> {
    ...
}

注記

他の JSR-330 実装との互換性を確保するために、@Dependent を除くすべての pseudo-scope アノテーションは bean 定義アノテーションではありません。ただし、pseudo-scope アノテーションを含む stereotype アノテーションは bean 定義アノテーションです。

7.2.2. スキャンプロセスからの Bean の除外

除外フィルターは、Bean アーカイブの beans.xml ファイルの <exclude> 要素によって <scan> 要素の子として定義されます。デフォルトでは、除外フィルターはアクティブです。定義に以下のものが含まれる場合、除外フィルターは非アクティブになります。

  • name 属性を含む、<if-class-available> という名前の子要素。 Bean アーカイブのクラスローダーはこの名前のクラスをロードできません。
  • name 属性を含む、<if-class-not-available> という名前の子要素。 Bean アーカイブのクラスローダーはこの名前のクラスをロードできます。
  • name 属性を含む、<if-system-property> という名前の子要素。 この名前に対して定義されたシステムプロパティーはありません。
  • name 属性と値属性を含む、<if-system-property> という名前の子要素。 この名前とこの値に対して定義されたシステムプロパティーはありません。

フィルターがアクティブな場合、タイプは検出から除外され、以下のいずれかの状態になります。

  • 検出されるタイプの完全修飾名が、除外フィルターの名前属性の値に一致します。
  • 検出されるタイプのパッケージ名が、除外フィルターの接尾辞 ".*" を含む名前属性の値に一致します。
  • 検出されるタイプのパッケージ名が、除外フィルターの接尾辞 ".*" を含む名前属性の値で始まります。

例7.1 例: beans.xml ファイル

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee">

    <scan>
        <exclude name="com.acme.rest.*" /> 1

        <exclude name="com.acme.faces.**"> 2
            <if-class-not-available name="javax.faces.context.FacesContext"/>
        </exclude>

        <exclude name="com.acme.verbose.*"> 3
            <if-system-property name="verbosity" value="low"/>
        </exclude>

        <exclude name="com.acme.ejb.**"> 4
            <if-class-available name="javax.enterprise.inject.Model"/>
            <if-system-property name="exclude-ejbs"/>
        </exclude>
    </scan>

</beans>
1
最初の除外フィルターにより、com.acme.rest パッケージ内のすべてのクラスが除外されます。
2
2 番目の除外フィルターにより、com.acme.faces パッケージとすべてのサブパッケージ内のすべてのクラスが除外されます (JSF が利用可能でない場合のみ)。
3
3 番目の除外フィルターにより、システムプロパティー verbosity が値 low を持つ場合に、com.acme.verbose パッケージ内のすべてのクラスが除外されます。
4
4 番目の除外フィルターにより、システムプロパティー exclude-ejbs が任意の値で設定され、javax.enterprise.inject.Model クラスがクラスローダーでも利用可能な場合に、com.acme.ejb パッケージとすべてのサブパッケージ内のすべてのクラスが除外されます。
注記

Java EE コンポーネントに @Vetoed アノテーションを付けて Java EE コンポーネントが Bean と見なされないようにすることができます。イベントは @Vetoed アノテーションが付けられたタイプに対して実行されず、また @Vetoed アノテーションが付けられたパッケージでは実行されません。詳細は@Vetoedを参照してください。

7.2.3. インジェクションを使用した実装の拡張

インジェクションを使用して、既存のコードの機能を追加または変更できます。

この例では、既存のクラスに翻訳機能を追加します。こメソッド buildPhrase を持つ Welcome クラスがすでにあることを前提とします。buildPhrase メソッドは、都市の名前を引数として取得し、「Welcome to Boston!」などのフレーズを出力します。

この例では、想像上の Translator オブジェクトが Welcome クラスにインジェクトされます。Translator オブジェクトは、文をある言語から別の言語に翻訳できる EJB ステートレス Bean または別のタイプの Bean になります。この例では、Translator は挨拶全体を翻訳するために使用され、元の Welcome クラスは変更されません。Translator は、buildPhrase メソッドが呼び出される前にインジェクトされます。

例: Translator bean の Welcome クラスへのインジェクト

public class TranslatingWelcome extends Welcome {

    @Inject Translator translator;

    public String buildPhrase(String city) {
        return translator.translate("Welcome to " + city + "!");
    }
    ...
}