CDIでの依存性注入。 パート1

ご使用の環境でCDI開始する方法に関する記事と、 CDIを既存のJava EE 6アプリケーション統合する方法に関するいくつかのヒントの後、依存性注入について説明します。 はい、シンプルな実装、またはあるBeanの実装を別のBeanに実装する方法について 。 この一連の3つの記事( パート2パート3 )から、さまざまな方法があることがわかります。最も単純な、通常の実装から始めましょう。







COFFEE_BEANS







デフォルトの展開



実装する最も簡単な方法...シンプル。 何かがあり、そこに何かを埋め込みます。 なぜ私はかという言葉を使っているのですか? Java EE 5より前は、特定のコンポーネント(EJBおよびサーブレット)にのみリソース(EntityManager、Datasource、JMSファクトリー)を埋め込むことができたためです。 CDIを使用すると、ほとんどすべてを何にでも埋め込むことができます。







この記事では、次のソフトウェアを使用しました。









実装を説明するために、 以前の記事Java EE 6の本と同じ例を使用します(Antonioは、 Beginning Java EE 7 [ translation ]-およそTrans。でも同じ例を使用します)。







CDI_CLASS_DIAGRAM







クラス図には、次のコンポーネントが示されています。









ご覧のとおり、 @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修飾子があります。









指定子は、型をその実装に関連付けるセマンティックコンストラクトです。 たとえば、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つの修飾子を非常に簡単に定義しました。 どうすれば今すぐ使用できますか? 図を見てみましょう:







CDI_CLASS_DIAGRAM_QUALIFIER







まず、指定子は対応する実装に注釈を付ける必要があります。 ご覧のとおり、 @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年に公開された記事。







次の記事では、 さまざまな実装ポイントを見ていきます。







ソースコード



コードダウンロードして、あなたがそれについてどう思うか教えてください。








All Articles