ご使用の環境でCDIを開始する方法に関する記事と、 CDIを既存のJava EE 6アプリケーションに統合する方法に関するいくつかのヒントの後、依存性注入について説明します。 はい、シンプルな実装、またはあるBeanの実装を別のBeanに実装する方法について 。 この一連の3つの記事( パート2 、 パート3 )から、さまざまな方法があることがわかります。最も単純な、通常の実装から始めましょう。
デフォルトの展開
実装する最も簡単な方法...シンプル。 何かがあり、そこに何かを埋め込みます。 なぜ私は何かという言葉を使っているのですか? Java EE 5より前は、特定のコンポーネント(EJBおよびサーブレット)にのみリソース(EntityManager、Datasource、JMSファクトリー)を埋め込むことができたためです。 CDIを使用すると、ほとんどすべてを何にでも埋め込むことができます。
この記事では、次のソフトウェアを使用しました。
- Java SE 1.6.0_23
- Glassfish 3.1
- Maven 3.0.2
実装を説明するために、 以前の記事やJava EE 6の本と同じ例を使用します(Antonioは、 Beginning Java EE 7 [ translation ]-およそTrans。でも同じ例を使用します)。
クラス図には、次のコンポーネントが示されています。
-
Book
は、いくつかの属性と名前付きクエリを備えたシンプルなJPAエンティティです -
ItemEJB
は、EntityManagerを使用してブックに対してCRUD操作を実行するEJB(インターフェースなし)です。 -
IsbnGenerator
-ISBNの乱数を生成する単純なPOJOクラス(ブックに使用) -
ItemRestService
をItemRestService
アノテーション(JAX-RSのRESTサービスを示す)でItemEJB
委任するCRUD操作 -
ItemServlet
は、ItemEJB
を使用してデータベースのすべての書籍を表示するサーブレットです。
ご覧のとおり、 @PersistenceContext
を使用して実装されるEntityManagerを除き、他のすべてのコンポーネントは@Inject
アノテーションによって埋め込まれています。 EntityManagerへのリンクを取得するItemEJB
コードの数行はItemEJB
です。
@Stateless public class ItemEJB { @PersistenceContext(unitName = "cdiPU") private EntityManager em; ... }
ItemEJB
とIsbnGenerator
へのリンクを両方とも埋め込むため、 ItemServlet
とItemRestService
非常に似ています。
@WebServlet(urlPatterns = "/itemServlet") public class ItemServlet extends HttpServlet { @Inject private IsbnGenerator numberGenerator; @Inject private ItemEJB itemEJB; ... }
IsbnGenerator
は最も一般的なPOJOです。 誰からも継承されず、いかなる方法でも注釈が付けられません。
public class IsbnGenerator { public String generateNumber () { return "13-84356-" + Math.abs(new Random().nextInt()); } }
これらのすべての場合、選択できる実装は1つだけです(1つのItemEJB
と1つのIsbnGenerator
のみがあります)。 実装が1つしかない場合、CDIはそれを実装できます。 次に、 デフォルトの実装について説明します 。
実際のコード:
@Inject IsbnGenerator numberGenerator
次のように書くことができます:
@Inject @Default IsbnGenerator numberGenerator
@Default
は組み込みの指定子で、CDIにデフォルトで実装を実装する必要があることを通知します。 修飾子なしでBeanを定義すると、 @Default
によって自動的に指定され@Default
。 次のコードは前のコードと同じです。
@WebServlet(urlPatterns = "/itemServlet") public class ItemServlet extends HttpServlet { @Inject @Default private IsbnGenerator numberGenerator; ... } @Default public class IsbnGenerator { public String generateNumber () { return "13-84356-" + Math.abs(new Random().nextInt()); } }
実装にIsbnGenerator
実装が1つしかない場合、デフォルトのハンドラーが機能し、通常の@Inject
がそのIsbnGenerator
を果たします。 ただし、いくつかの実装から選択することが必要な場合があり、その後、 指定子が作用します。
この記事では、 Beanという用語を使用しますが、より正確には、 マネージドBean (たとえば、 CDIによって制御されるBean )と言う必要があります。 ManagedBeansはJava EE 6で導入されました。
あいまいな実装と修飾子
ビンの種類によっては、 このタイプを実装するビンがいくつか存在する場合があります。 たとえば、アプリケーションにはNumberGenerator
インターフェースの2つの実装がありますIsbnGenerator
は13桁の数値を生成し、 IssnGenerator
は8桁を生成します。 13桁の数値を生成する必要のあるコンポーネントは、何らかの方法で2つの実装を区別する必要があります。 1つのオプションは、クラス( IsbnGenerator
)を明示的に指定することですが、その後、コンポーネントと実装の間に厳しい関係が作成されます。 別のオプションは、外部XML構成で適切なBeanの実装を記述することです。 CDIは注釈指定子を使用して、強い型付けと弱い接続を取得します。
この記事では、クラスのフィールド(属性)を介した埋め込みを使用しますが、CDIでは、セッターまたはコンストラクターを介した埋め込みも使用できます。
ある目的のために、 ItemServlet
が13桁のISBN番号で本を作成し、8桁のISSN番号でItemRestService
をItemRestService
とします。 両方のクラス( ItemServlet
とItemRestService
)には同じNumberGenerator
インターフェースへの埋め込みリンクがありますが、 NumberGenerator
どの実装が使用されますか? 知らないの? CDIも認識せず、エラーメッセージが表示されます。
注入ポイント[[フィールド] @Inject private ItemRestService.numberGenerator]での修飾子[@Default]を持つタイプ[NumberGenerator]のあいまいな依存関係。 可能な依存関係[[Managed Bean [class IsbnGenerator] with qualifiers [@Any @Default]、Managed Bean [class IssnGenerator] with qualifiers [@Any @Default]]]。
これは、あいまいさを取り除き、CDI、どのビン、どこを実装する必要があるかを示す必要があることを意味します。 以前にSpringを使用したことがある場合、最初に思い浮かぶのは「 beans.xmlを使用しましょう 」です。 しかし、 この投稿にあるように、「 beans.xmlは、beanが定義されているXMLではありません 。」 CDIでは、修飾子(注釈)を使用する必要があります。
3つの組み込み CDI修飾子があります。
-
@Default
:Beanの定義に修飾子が含まれていない場合、@Default
修飾子があります -
@Any
:アプリケーションが指定子を動的に定義できるようにします -
@New
:アプリケーションが新しい指定されたBeanを受信できるようにします(CDI 1.1では、@New
は廃止@New
と見なされます -約
指定子は、型をその実装に関連付けるセマンティックコンストラクトです。 たとえば、13桁の数値 ジェネレーターまたは8 桁の数値 ジェネレーターを表す修飾子を入力できます。 Javaでは、修飾子は@Target({FIELD, TYPE, METHOD})
および@Retention(RUNTIME)
として定義された注釈によって表されます。 次のように、メタアノテーション@javax.inject.Qualifier
れます。
@Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD}) public @interface EightDigits { } @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD}) public @interface ThirteenDigits { }
ご覧のとおり、2つの修飾子を非常に簡単に定義しました。 どうすれば今すぐ使用できますか? 図を見てみましょう:
まず、指定子は対応する実装に注釈を付ける必要があります。 ご覧のとおり、 @ThirteenDigit
注釈を付け、 @ThirteenDigit
はIsbnGenerator
を@EightDigit
IssnGenerator
。
@EightDigits public class IssnGenerator implements NumberGenerator { public String generateNumber() { return "8-" + Math.abs(new Random().nextInt()); } } @ThirteenDigits public class IsbnGenerator implements NumberGenerator { public String generateNumber() { return "13-84356-" + Math.abs(new Random().nextInt()); } }
次に、 NumberGenerator
インターフェイスへのリンクがNumberGenerator
れるコンポーネントを次のように実装する必要があります。
@WebServlet(urlPatterns = "/itemServlet") public class ItemServlet extends HttpServlet { @Inject @ThirteenDigits private NumberGenerator numberGenerator; ... } @Path("/items") @ManagedBean public class ItemRestService { @Inject @EightDigits private NumberGenerator numberGenerator; ... }
外部設定は必要ありません。 これが、CDIに厳密な型指定が必要な理由です。 実装の名前は自由に変更できますが、実装ポイントは変更されません(これは弱い接続です)。 また、Beanはいくつかの修飾子で宣言できることに注意してください。 ご覧のとおり、CDIはタイプセーフな依存性注入を行うエレガントな方法です。 しかし、何かを実装する必要があるたびに注釈の作成を開始すると、コードが読みにくくなります。 この場合、転送が役立ちます。
列挙型の修飾子
実装を選択する必要があるたびに、注釈を作成します。 次に、追加の2桁の番号 ジェネレーターまたは10桁の番号ジェネレーターが必要な場合は、より多くの注釈を作成します。 XMLの地獄からアノテーションの地獄に移行しているようです! それらの乗算を回避する1つの方法は、次のように列挙を使用することです。
@WebServlet(urlPatterns = "/itemServlet") public class ItemServlet extends HttpServlet { @Inject @NumberOfDigits(Digits.THIRTEEN) private NumberGenerator numberGenerator; ... } @Path("/items") @ManagedBean public class ItemRestService { @Inject @NumberOfDigits(Digits.EIGHT) private NumberGenerator numberGenerator; ... } @NumberOfDigits(Digits.THIRTEEN) public class IsbnGenerator implements NumberGenerator { public String generateNumber() { return "13-84356-" + Math.abs(new Random().nextInt()); } } @NumberOfDigits(Digits.EIGHT) public class IssnGenerator implements NumberGenerator { public String generateNumber() { return "8-" + Math.abs(new Random().nextInt()); } }
ご覧のとおり、 @ThirteenDigits
および@EightDigits
を@NumberOfDigit
、列挙が注釈の値として使用される@NumberOfDigit
のみを使用しています。 ここにあなたが書くべきコードがあります:
@Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD}) public @interface NumberOfDigits { Digits value(); } public enum Digits { TWO, EIGHT, TEN, THIRTEEN }
おわりに
あなたについては知りませんが、CDIは大好きです。 XMLを使用せずに 、CDI タイプセーフが通常のJavaのBeanをバインドする方法が本当に気に入っています 。 はい、すべてが美しいとは限りません。 私が最初に目にするのは、コード内の注釈の数の増加です。 転送のおかげで、これは制限される可能性があります。 2番目はIDEのサポートです。 IDEは次のことを知っている必要があります。
@Inject @NumberOfDigits(Digits.EIGHT) NumberGenerator numberGenerator
IssnGenerator
参照しIssnGenerator
。 IDEのサポートについては、このトピックに深く精通しているとは言えません。 私はIntellij IDEAを使用していますが、そのCDIサポートは驚くばかりです。 Beanの実装について考えることなく、Bean間を移動できます。 NetBeansにもいくつかのサポートが実装されていると思います...しかし、Eclipseにあるのではないかと思います; o)(2011年に公開された記事。
次の記事では、 さまざまな実装ポイントを見ていきます。
ソースコード
コードをダウンロードして、あなたがそれについてどう思うか教えてください。