7.2. Contexts and Dependency Injection を使用したアプリケーションの開発

コンテキストと依存関係の注入 (CDI: Contexts and Dependency Injection) を使用すると、アプリケーションの開発、コードの再利用、デプロイメント時または実行時のコードの調整、およびユニットテストを非常に柔軟に行うことができます。

Weld にはアプリケーション開発の特別なモードが含まれています。有効にすると、Contexts and Dependency Injection アプリケーションの開発を容易にする特定の組み込みツールを利用できます。

注記

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

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 定義アノテーションを持たないオブザーバーメソッドが検出されません。
重要

Contexts and Dependency Injection セクションのすべての例は、検出モードが 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 実装および Jakarta Contexts and Dependency Injection 仕様との互換性を確保するために、@Dependent を除くすべての擬似スコープアノテーションは 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 パッケージとすべてのサブパッケージ内のすべてのクラスが除外されます (Jakarta Server Faces が利用可能でない場合のみ)。
3
3 番目の除外フィルターにより、システムプロパティー verbosity が値 low を持つ場合に、com.acme.verbose パッケージ内のすべてのクラスが除外されます。
4
4 番目の除外フィルターにより、システムプロパティー exclude-ejbs が任意の値で設定され、javax.enterprise.inject.Model クラスがクラスローダーでも利用可能な場合に、com.acme.ejb パッケージとすべてのサブパッケージ内のすべてのクラスが除外されます。
注記

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

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

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

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

この例では、想像上の Translator オブジェクトが Welcome クラスにインジェクトされます。Translator オブジェクトは、文をある言語から別の言語に翻訳できる Enterprise Java Bean ステートレス 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 + "!");
    }
    ...
}