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

このブログをフォローしている場合は、CDI( Contexts and Dependency Injection )について最近書いている(そして話す )ことを覚えておいてください。 CDIにはさまざまな側面がありますが、これまでのところ、環境でCDI開始する方法と、 CDIを既存のJava EE 6アプリケーション統合する方法に焦点を当て、CDIでの依存性注入に焦点を当てました。 これはCDIでの実装に関する3番目の投稿です。 最初はデフォルトの実装と修飾子について、 2番目はすべての可能な実装ポイント(フィールド、コンストラクタ、セッター)について説明しました。 この投稿では、 プロデューサー、または「 タイプセーフな方法で何でもどこでも実装できる方法について説明します







COFFEE_BEANS







Beanのみをデプロイしますか?



その前に、通常の@Inject



アノテーションを使用して@Inject



を注入する方法を示しました。 先ほど使用した書籍番号の生成の例を見ると、 NumberGenerator



インターフェースの実装が実装されているサーブレットとレストサービスが表示されます。 修飾子のおかげで、サーブレットは実装ポイントで@ThirteenDigit



IsbnGenerator



マークされたIsbnGenerator



を受け取ることができ、残りのサービスはIssnGenerator



マークされた@EightDigits



を受け取ります(私の最初の投稿を参照)。 提示されたクラス図は、Beanインジェクションのいくつかの組み合わせを示しています。







CDI_3_1







しかし、ご覧のとおり、これはすべて他のBeanへのBeanの注入です 。 CDIでのみBeanを実装できますか? いや 何でもどこでも実装できます







プロデューサー



はい、何でもどこでも実装できます。 これのためにしなければならないことは、後で実装したいもの作成することです。 CDI( Factoryパターンの優れた実装)には、このためのプロデューサーがいます。 彼らの助けを借りて、次のものを作成できます。







  • クラス:Beanの数に制限のないタイプ、そのスーパークラス、および実装するすべてのインターフェース
  • インターフェース:無制限の数のBeanタイプ、その拡張インターフェース、およびjava.lang.Object



  • プリミティブとJava配列


したがって、 java.util.Date



java.lang.String



またはint



埋め込むこともできjava.lang.String



。 いくつかのタイプのデータとプリミティブを作成して実装することから始めましょう。







データ型とプリミティブ型の作成



何でもどこにでも埋め込む方法の1つの例は、データ型とプリミティブの実装です。 それでは、 String



int



を実装してみましょう。 これを行うには、モデルにクラスを追加する必要があります。 これに先立ち、 IsbnGenerator



の形式で乱数を作成しました。 この番号は、接頭辞( 13-124 )として機能する文字列と、整数値-接尾辞( 4 )で構成されます。 次のクラス図は、数値を生成するために使用されるPrefixGenerator



PostfixGenerator



2つの新しいクラスを示しています。







CDI_3_2







たとえば、 PrefixGenerator



のコードを見ると、メソッドとは対照的に、修飾子でマークされていないクラスが表示されます。 getIsbnPrefix



メソッドは、 @ThirteenDigits



アノテーションで指定された文字列を返します。 この行は、CDIを使用して作成されます( @ThirteenDigits



)。 @ThirteenDigits



とその修飾子( @ThirteenDigits



)を使用して埋め込むことができます。







 public class PrefixGenerator { @Produces @ThirteenDigits public String getIsbnPrefix() { return "13-84356"; } @Produces @EightDigits public String getIssnPrefix() { return "8"; } }
      
      





次に、 PostfixGenerator



クラスを注意深く見てください。 このコードは前のコードと似ていますが、組み込み可能なint



作成する点が異なります。







 public class PostfixGenerator { @Produces @ThirteenDigits public int getIsbnPostfix() { return 13; } @Produces @EightDigits public int getIssnPostfix() { return 8; } }
      
      





次に、ISBN番号を生成するロジックを変更しましょう。 @Inject



@ThirteenDigits



を使用して、 String



int



@Inject



埋め込まれます。 これで、CDIでの厳密な型指定の意味が理解できました。 この構文( @Inject @ThirteenDigits



)を使用して、CDIはString



代わりに埋め込む必要があるもの、intのNumberGenerator



もの、およびNumberGenerator



実装をNumberGenerator









 @ThirteenDigits public class IsbnGenerator implements NumberGenerator { @Inject @ThirteenDigits private String prefix; @Inject @ThirteenDigits private int postfix; public String generateNumber() { return prefix + "-" + Math.abs(new Random().nextInt()) + "-" + postfix; } }
      
      





プロデューサーフィールドを介したJava EEリソースのデプロイ



それで、CDIが文字列と整数を埋め込むことができるとしても、CDIが何でもどこにでも埋め込むことができるなら、Java EEリソースはどうでしょうか? これは別の話です。プロデューサーはこれを手伝ってくれます。 前述したように、CDIではすべてがタイプセーフであるため、CDI にJNDI名リソースを埋め込む方法はありません。たとえば、 @Inject(name="jms/OrderQueue")



ます。 標準的な例は、エンティティマネージャです。 CDIを使用していない場合、Java EE 6では次のように実装できます。







 @Stateless public class ItemEJB { @PersistenceContext(unitName = "cdiPU") private EntityManager em; ... }
      
      





それでは、エンティティマネージャに対して通常の@Inject



を作成できないのはなぜですか? 実装のあいまいさに関する最初の投稿を覚えているなら、同じ問題です。 いくつかの永続性ユニット(通常の文字列と呼ばれる)を持つことができ、単に@Inject



記述すると、CDIはどのユニットを実装する必要があるかを判断できません。 代わりに、エンティティマネージャーを最初に作成し、なんとか名前を付ける必要があります( @Default



を使用したくない場合):







 public class DatabaseProducer { @Produces @PersistenceContext(unitName = "cdiPU") @BookStoreDatabase private EntityManager em; }
      
      





DatabaseProducer



クラスは@PersistenceContext



を使用して、cdiPU永続性ユニットでエンティティマネージャーを実装します。 指定子( @BookStoreDatabase



)でマークされ、初期化されます。その後、次のようにEJBに埋め込むことができます。







 @Stateless public class ItemEJB { @Inject @BookStoreDatabase private EntityManager em; ... }
      
      





別の良い例は、JMSファクトリーと宛先の作成です。 @Resource



使用すると、JMSファクトリまたは送り先へのJNDIリンクを取得でき、 @Order



がそれに名前を付け、 @Produces



使用して後で実装できます。







 public class JMSResourceProducer { @Produces @Order @Resource(name = "jms/OrderConnectionFactory") private QueueConnectionFactory orderConnectionFactory; @Produces @Order @Resource(name = "jms/OrderQueue") private Queue orderQueue; }
      
      





これで、EJBはタイプセーフな@Inject



使用できます。







 @Stateless public class ItemEJB { @Inject @Order private QueueConnectionFactory orderConnectionFactory; @Inject @Order private Queue orderQueue; ... }
      
      





プロデューサーメソッドを使用したJava EEリソースの作成



考えられる例は非常に単純です。フィールドを作成してから、それを実装できます。 これは生産フィールドと呼ばれます。 ただし、Beanを作成するためにより複雑なビジネスロジックが必要になる場合があり、これをプロデューサーメソッドと呼びます。 別の例を見てみましょう。 JMSメッセージを送信する必要がある場合は、メッセージを送信するまで、常にJMSファクトリーと宛先(キューまたはトピック)を実装し、接続を作成してからセッションなどを作成します。 このコードは頻繁に繰り返され、エラーが含まれる可能性があるため、別のクラスのどこかに置いて、メッセージの送信に必要なセッションや他のコンポーネントを作成するために使用してみませんか? このクラスは次のようになります。







 public class JMSResourceProducer { @Resource(name = "jms/OrderConnectionFactory") private QueueConnectionFactory orderConnectionFactory; @Produces @Order @Resource(name = "jms/OrderQueue") private Queue orderQueue; @Produces @Order public QueueConnection createOrderConnection() throws JMSException { return orderConnectionFactory.createQueueConnection(); } @Produces @Order public QueueSession createOrderSession(@Order QueueConnection conn) throws JMSException { return conn.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); } }
      
      





まず、クラスは@Resource



を使用してQueueConnectionFactory



およびQueue



へのリンクを取得します。 上記で説明したのと同じ理由で、複数のJMSファクトリーと宛先があり、それらをJNDI名で区別する必要があります。 また、CDIでは注入ポイントで名前を指定できないため、 @Inject



ではなく@Resource



を使用する必要があります。 createOrderConnection



メソッドはQueueConnectionFactory



を使用してQueueConnectionFactory



を作成し、さらに(それを@Order



@Order



て)実装します。 createOrderSessionメソッドをよく見ると、そのパラメーターはQueueConnection



を実装するために以前に作成されたものQueueConnection



あり、その助けを借りてQueueSession



が作成されていることがわかります。 その結果、JMSセッションを作成せずに外部コンポーネントに埋め込むのは非常に簡単です。







 @Stateless public class ItemEJB { @Inject @Order private QueueSession session; @Inject @Order private Queue orderQueue; private void sendOrder(Book book) throws Exception { QueueSender sender = session.createSender(orderQueue); TextMessage message = session.createTextMessage(); message.setText(marshall(book)); sender.send(message); } ... }
      
      





作成と廃棄



「わかりました、大まかな作業を行い、接続とセッションを作成するための外部クラスがあります ... しかし、誰がそれらを閉じますか? 」 そしてこの時点で、CDIはさらに魔法を示します: @Disposes









 public class JMSResourceProducer { @Resource(name = "jms/OrderConnectionFactory") private QueueConnectionFactory orderConnectionFactory; @Produces @Order @Resource(name = "jms/OrderQueue") private Queue orderQueue; @Produces @Order public QueueConnection createOrderConnection() throws JMSException { return orderConnectionFactory.createQueueConnection(); } @Produces @Order public QueueSession createOrderSession(@Order QueueConnection conn) throws JMSException { return conn.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); } public void closeOrderSession(@Disposes @Order QueueConnection conn) throws JMSException { conn.close(); } public void closeOrderSession(@Disposes @Order QueueSession session) throws JMSException { session.close(); } }
      
      





CDIにリソースを閉じるように依頼するには、このリソースを作成したメソッド( createOrderSession(@Order QueueConnection conn)



がセッションを作成し、 closeOrderSession(@Order QueueConnection conn)



を閉じて閉じるcloseOrderSession(@Order QueueConnection conn)



に類似したメソッドを定義し、 @Disposes



アノテーションを追加する@Disposes



です。 CDIは、正しい順序でリソースをリサイクルします(最初にセッション、次に接続)。 これについては言及しませんでしたが、CDIはその範囲(要求、セッション、アプリケーション、会話など)に応じてリソースを作成および利用します。 しかし、その別の時間についての詳細。 (情報は、 Java EE 7の始まり [ 翻訳 ]-約です。)







おわりに



以前の投稿( パート1パート2 )から理解したように、CDIは依存性注入に関するものです。 これまで、Beanを注入する方法を示しましたが、どこでも(文字列、プリミティブ、エンティティマネージャー、JMSファクトリー...)どこでも(POJO、サーブレット、EJBなど)を実装する方法を知っています。 実装するものを作成するだけです(プロデュースフィールドまたはプロデュースメソッドのいずれかを使用)。







ソースコード



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








All Articles