7.2. CDI を使用したアプリケーションの開発
コンテキストと依存関係の注入 (CDI: Contexts and Dependency Injection) を使用すると、アプリケーションの開発、コードの再利用、デプロイメント時または実行時のコードの調整、およびユニットテストを非常に柔軟に行うことができます。JBoss EAP には、CDI の参照実装である Weld が含まれます。これらのタスクは、エンタープライズアプリケーションで CDI を使用する方法を示しています。
Weld にはアプリケーション開発の特別なモードが含まれています。開発モードを有効にすると、CDI アプリケーションの開発を容易にする一部のビルドインツールが利用できます。
アプリケーションのパフォーマンスに悪影響を与えるため、開発モードは本番環境では使用しないでください。必ずデプロイメントモードを無効にしてから本番環境にデプロイしてください。
Web アプリケーションに対して開発モードを有効にするには、以下を行います。
Web アプリケーションの場合、サーブレット初期化パラメーター org.jboss.weld.development
を true
に設定します。
<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 + "!"); } ... }