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.Datejava.lang.Stringまたはint埋め込むこともできjava.lang.String 。 いくつかのタイプのデータとプリミティブを作成して実装することから始めましょう。


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


何でもどこにでも埋め込む方法の1つの例は、データ型とプリミティブの実装です。 それでは、 Stringintを実装してみましょう。 これを行うには、モデルにクラスを追加する必要があります。 これに先立ち、 IsbnGeneratorの形式で乱数を作成しました。 この番号は、接頭辞( 13-124 )として機能する文字列と、整数値-接尾辞( 4 )で構成されます。 次のクラス図は、数値を生成するために使用されるPrefixGeneratorPostfixGenerator 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を使用して、 Stringint@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など)を実装する方法を知っています。 実装するものを作成するだけです(プロデュースフィールドまたはプロデュースメソッドのいずれかを使用)。


ソースコード


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



Source: https://habr.com/ru/post/J302010/


All Articles