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.*" />
<exclude name="com.acme.faces.**">
<if-class-not-available name="javax.faces.context.FacesContext"/>
</exclude>
<exclude name="com.acme.verbose.*">
<if-system-property name="verbosity" value="low"/>
</exclude>
<exclude name="com.acme.ejb.**">
<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 + "!");
}
...
}