Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

Beginning Java EE 6 勉強会(5) #bje_study

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Wird geladen in …3
×

Hier ansehen

1 von 68 Anzeige
Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Andere mochten auch (20)

Anzeige

Ähnlich wie Beginning Java EE 6 勉強会(5) #bje_study (20)

Aktuellste (20)

Anzeige

Beginning Java EE 6 勉強会(5) #bje_study

  1. 1. Beginning JavaEE6 勉強会(5) -メッセージ通信- Jun. 13, 2012
  2. 2. ggrks 目次 @見たな 13. メッセージ通信  メッセージング  JMS  MDB 2012/6/12 Beginning JavaEE6 勉強会(5) 2
  3. 3. メッセージング 2012/6/12 Beginning JavaEE6 勉強会(5) 3
  4. 4. メッセージ指向ミドルウェア • メッセージング処理 – 異種システム間対応可能 – 非同期通信 • メッセージ指向ミドルウェア(MOM) – 上記処理を可能にするソフトウェア – 通信内容(メッセージ)の生成・消費ペースを 調整するバッファとして機能する – メッセージの形式と「宛先」について合意する だけで疎結合なシステム連携が実現できる • RPC (Remote Procedure Call)の場合、 メソッドシグネチャまで合意しなければならない 2012/6/12 Beginning JavaEE6 勉強会(5) 4
  5. 5. 13.1 メッセージとは • MOMの用語 メッセージ プロバイダ (別名:ブローカ) メッセ ージ プロデューサ コンシューマ 宛先 送信 受信 メッセージの流れ 2012/6/12 Beginning JavaEE6 勉強会(5) 5
  6. 6. 13.1 メッセージとは • MOMの用語 メッセージを溜め、振り分ける ソフトウェア メッセージ 連携データ プロバイダ メッセージを受けて (別名:ブローカ) 処理するコンポーネント メッセ ージ プロデューサ コンシューマ 宛先 送信 受信 メッセージの格納場所 メッセージを他の メッセージプロバイダ内に複数作れる コンポーネントに メッセージの流れ 送信するコンポー ネント 2012/6/12 Beginning JavaEE6 勉強会(5) 6
  7. 7. 13.1 メッセージとは • JMS (Java Message Service) – メッセージの処理をJavaアプリケーションから行う ためのAPI – JDBCが複数データベース製品に対応するように、 JMSも製品を抽象化し複数製品に対応できる • メッセージ・ドリブンBean(MDB) – メッセージを受けて起動したい処理があるとき、 EJBコンテナにメッセージの定期的な監視と受信を 任せることができる仕組み – ステートレス. メッセージ間で独立して起動 – 実際の処理はステートレスBeanに移譲してもよい 2012/6/12 Beginning JavaEE6 勉強会(5) 7
  8. 8. 13.2 メッセージングの仕様の概要 • 簡単な歴史 – 1980後半 システム間連携の方法なし 各社低レベルプロトコルで作りこみ そこでMOMが登場 – 1998 JMS 1.0 仕様公開 – 2001 EJB 2.0にMDBが採用 – 2002 JMS 1.1 仕様公開 – 2006 EJB 3.0でMDBにアノテーションが採用 – 2006 OpenMQが参照実装としてオープンソース化 – 2012 JMS 2.0 仕様公開予定(JSR 343) 2012/6/12 Beginning JavaEE6 勉強会(5) 8
  9. 9. 書籍外 13.2 メッセージングの仕様の概要 • 簡単な歴史 – 1950 コンピュータ誕生 – 1980s メインフレームの時代 – 1990s オープンシステムが台頭 システム間連携を個別に作りこむ必要性が発生 – 1993 IBM MQSeries V1 発表 MOM乱立 – 1998 JMS 1.0 仕様公開 – 2001 EJB 2.0にMDBが採用 – 2002 IBM WebSphere MQ V5.3 (改名した) – 2002 JMS 1.1 仕様公開 – 2006 EJB 3.0でMDBにアノテーションが採用 – 2006 SunのOpenMQが参照実装としてオープンソース化 ポイント 10年間 – 2012 JMS 2.0 仕様公開予定(JSR 343) 仕様変更 なし 2012/6/12 Beginning JavaEE6 勉強会(5) 9
  10. 10. 書籍外 JMSプロバイダの実装 • Wikipedia によると以下の通り – Apache ActiveMQ – Apache Qpid, using AMQP – EMS from TIBCO – OpenJMS, from The OpenJMS Group – JBoss Messaging and HornetQ from JBoss – JORAM, from the OW2 Consortium – Open Message Queue, from Sun Microsystems – BEA Weblogic (part of the Fusion Middleware suite) and Oracle AQ from Oracle – RabbitMQ, using AMQP – Solace JMS from Solace Systems – SonicMQ from Progress Software – StormMQ, using AMQP – SwiftMQ – Tervela – webMethods from Software AG – WebSphere Application Server from IBM, which provides an inbuilt default messaging provider known as the Service Integration Bus (SIBus), or which can connect to WebSphere MQ as a JMS provider [5] – WebSphere MQ (formerly MQSeries) from IBM – Ultra Messaging from 29 West (acquired by Informatica) • TheServerSide.comに比較表もある – http://www.theserverside.com/matrix 2012/6/12 Beginning JavaEE6 勉強会(5) 10
  11. 11. 13.3 メッセージを送受信する方法 • 以下の簡単なモデルでJMSだけを試す – 作成するのはSenderとReceiverクラスだけ – 他は設定とAPIを呼ぶのみ OpenMQ NetBeans同梱の Glassfishサーバに メッセ 同梱されている ージ Sender Receiver Queue main() 受信 main() 送信 メッセージの流れ 2012/6/12 Beginning JavaEE6 勉強会(5) 11
  12. 12. Work#1 メッセージを送信する 作業手順 1. MOMを起動する 2. MOMに「管理対象オブジェクト」を作る 1. 宛先を作る 2. コネクションファクトリを作る 3. Javaでプロデューサ(Sender.java)を作る 4. Javaでコンシューマ(Receiver.java)を作る 5. ビルド 6. 動かす 2012/6/12 Beginning JavaEE6 勉強会(5) 12
  13. 13. Work#1-1 MOMを起動する • Glassfishに付属しているOpenMQを使うので、 単にGlassfishを起動する 2012/6/12 Beginning JavaEE6 勉強会(5) 13
  14. 14. Work#1-2 管理対象オブジェクトを作る • ブラウザでOpenMQの管理コンソールを開く – http://localhost:4848/ 2012/6/12 Beginning JavaEE6 勉強会(5) 14
  15. 15. Work#1-2-1 コネクションファクトリを作る • コネクションファクトリを作る – 下記3つだけ埋めてあとはデフォルトでよし jms/javaee6/ConnectionFactory javax.jms.ConnectionFactory jms/javaee6/ConnectionFactory 2012/6/12 Beginning JavaEE6 勉強会(5) 15
  16. 16. Work#1-2-2 宛先を作る • 宛先を作る。(Work#1では”Queue”を作る) – 下記4つだけ埋めてあとはデフォルトでよし jms/javaee6/Queue jms_javaee6_Queue javax.jms.Queue jms/javaee6/Queue 2012/6/12 Beginning JavaEE6 勉強会(5) 16
  17. 17. Work#1-3 プロデューサを作る • メッセージプロデューサ(生成側) – https://svn.kenai.com/svn/beginningee6~src/book/trunk/ をcheckout – “Chapter 13 - JMS (JMS)” プロジェクト – “org.beginningee6.book.chapter13.jms.ex01” パッケージ public class Sender { ※ package文、import文、コメント等は紙面の都合で削除 public static void main(String[] args) { try { Context jndiContext = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee6/ConnectionFactory"); Queue queue = (Queue) jndiContext.lookup("jms/javaee6/Queue"); Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(queue); TextMessage message = session.createTextMessage(); message.setText("This is a text message sent at " + new Date()); producer.send(message); System.out.println("nMessage sent !"); connection.close(); } catch (Exception e) { e.printStackTrace(); } System.exit(0); } } org.beginningee6.book.chapter13.jms.ex01.Sender を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 17
  18. 18. Work#1-4 コンシューマを作る • メッセージコンシューマ(消費側) – プロデューサと同様 public class Receiver { ※ package文、import文、コメント等は紙面の都合で削除 public static void main(String[] args) { try { Context jndiContext = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee6/ConnectionFactory"); Queue queue = (Queue) jndiContext.lookup("jms/javaee6/Queue"); Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(queue); connection.start(); System.out.println("nInfinite loop. Waiting for a message..."); while (true) { TextMessage message = (TextMessage) consumer.receive(); System.out.println("Message received: " + message.getText()); } } catch (Exception e) { e.printStackTrace(); } } } org.beginningee6.book.chapter13.jms.ex01.Receiver を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 18
  19. 19. Work#1-5-1 ビルド-mainClass指定 • pom.xmlを編集し、動かしたいクラスを <mainClass>に指定 2012/6/12 Beginning JavaEE6 勉強会(5) 19
  20. 20. Work#1-5-2 ビルド-実行 • 「依存関係で構築」または 「生成物を削除して構築」 2012/6/12 Beginning JavaEE6 勉強会(5) 20
  21. 21. Work#1-5 動かす(コマンドライン) • プロバイダを起動する(数回) – テキストメッセージが宛先に1つ送られる > appclient -client chapter13-JMS-2.0.jar ※1 C:Program Filesglassfish-3.1.2glassfishbinappclient ※2 C:Users (ユーザ名) DocumentsNetBeansProjectsbook chapter13jmstarget chapter13-JMS-2.0.jar • コンシューマを起動する (mainClass変えて生成する) – 送ったメッセージがすべて表示される > appclient -client chapter13-JMS-2.0.jar ※ デフォルトでは生成物名が同じなので注意 2012/6/12 Beginning JavaEE6 勉強会(5) 21
  22. 22. 補足1:JMSリソースをコマンドラインから操作 • JMSリソースはコマンドラインから操作可能 – 実は設定項目がわかっていればそちらの方が簡単 – コマンドはGlassfishに添付されている • C:Program Filesglassfish-3.1.2glassfishbinasadmin asadmin create-jms-resource --restype javax.jms.ConnectionFactory jms/javaee6/ConnectionFactory asadmin create-jms-resource --restype javax.jms.QueueConnectionFactory jms/javaee6/QConnectionFactory asadmin create-jms-resource --restype javax.jms.TopicConnectionFactory jms/javaee6/TConnectionFactory asadmin create-jms-resource --restype javax.jms.Queue jms/javaee6/Queue asadmin create-jms-resource --restype javax.jms.Topic jms/javaee6/Topic asadmin list-jms-resources 2012/6/12 Beginning JavaEE6 勉強会(5) 22
  23. 23. 補足2:スタンドアロンJMSクライアント • Work#1はコンテナ外からでも動かせる – この場合ライブラリを読み込む必要があるので注意 • 金魚本ではACC上で動かすようになっている – スタンドアロンのGlassfishインストールフォルダに 同梱されているライブラリを使う。 – 必要なファイルは以下の通り インストールフォルダは人によって異なる • C:Program Filesglassfish-3.1.2mqlibjms.jar • C:Program Filesglassfish-3.1.2mqlibjms.jar • C:Program Filesglassfish-3.1.2glassfishlibgf-client.jar 今回は面倒なので省略 2012/6/12 Beginning JavaEE6 勉強会(5) 23
  24. 24. 次の章に移る前にcheckout [1/2] • 金魚本公式からサンプルコードをcheckout – https://svn.kenai.com/svn/beginningee6~src/book/trunk/ • “Chapter 13 - JMS (JMS)” プロジェクト – “org.beginningee6.book.chapter13.jms.ex01” パッケージ →Work#1で終了 – “org.beginningee6.book.chapter13.jms.ex04” パッケージ →Java EE コンテナ上で動作する例 – “org.beginningee6.book.chapter13.jms.ex05” パッケージ →Java EE コンテナ上で動作する例。リスナを利用する – “org.beginningee6.book.chapter13.jms.ex07” パッケージ →Java EE コンテナ上で動作する例。セレクタを利用する – “org.beginningee6.book.chapter13.jms.ex14” パッケージ →オブジェクトを送信する例。MDB動作確認時の送信側スタブとして使う 2012/6/12 Beginning JavaEE6 勉強会(5) 24
  25. 25. 次の章に移る前にcheckout [2/2] (つづき) • “Chapter 13 - JMS (MDB)” プロジェクト – “org.beginningee6.book.chapter13.jms.ex08” パッケージ →MDBの例。 – “org.beginningee6.book.chapter13.jms.ex11” パッケージ →@MessageDrivenアノテーションの属性指定の例。 – “org.beginningee6.book.chapter13.jms.ex12” パッケージ →MDBのライフサイクル確認用の例。 @PostConstructと@PreDestroyの動作確認。今回は利用しない。 – “org.beginningee6.book.chapter13.jms.ex15” パッケージ →オブジェクトを処理するMDBの例。今回は利用しない。(時間がない) 2012/6/12 Beginning JavaEE6 勉強会(5) 25
  26. 26. Java Message Service 2012/6/12 Beginning JavaEE6 勉強会(5) 26
  27. 27. 13.4 Java Message Service • 構成 メッセージの生成 メッセージの使用 JMSプロバイダ プロデューサ コンシューマ JNDIディレクトリ 管理対象オブジェクトの 管理対象オブジェクトの ルックアップ ルックアップ 2012/6/12 Beginning JavaEE6 勉強会(5) 27
  28. 28. 13.4 Java Message Service • 構成 MOMのこと。別名:ブローカ メッセージのバッファや配信を制御 メッセージの生成 メッセージの使用 JMSプロバイダ メッセージを送受信するアプリ。 プロデューサ 「クライアント」と総称する。 コンシューマ ・送信側は、プロデューサ、センダ、 クライアント パブリッシャと呼ぶ。 ・受信側は、コンシューマ、 レシーバ、サブスクライバと呼ぶ。 JNDIディレクトリ 管理対象オブジェクトの 管理対象オブジェクトの ルックアップ ルックアップ 2012/6/12 Beginning JavaEE6 勉強会(5) 28
  29. 29. 13.4 Java Message Service • 用語 – JMSの世界では2つのモデルがあり、APIが違う 一般名 ポイント・ツー・ポイ パブリッシュ・サブスク ント ライブ Destination Queue Topic ConnectionFactory QueueConnectionFactory TopicConnectionFactory Connection QueueConnection TopicConnection Session QueueSession TopicSession MessageConsumer QueueReciever TopicReciever MessageProducer QueueSender TopicSender – 宛先(Destination)={Queue, Topic} – P2Pモデル →Queue – pub-subモデル→Topic 2012/6/12 Beginning JavaEE6 勉強会(5) 29
  30. 30. 1.3.4.1 P2Pモデル • ポイント・ツー・ポイント・モデル – メッセージに対してレシーバが1つの場合使う • レシーバが受信するとメッセージは消える • レシーバが複数ある場合、どれか1つにしか届かない • イメージ メッセージ メッセージ #1 メッセージ #1 #1 レシーバ メッセージ メッセージ #1 センダ 宛先 メッセージ #1 #1 送信 受信 2012/6/12 Beginning JavaEE6 勉強会(5) 30
  31. 31. 1.3.4.1 P2Pモデル • ポイント・ツー・ポイント・モデル – メッセージに対してレシーバが1つの場合使う • レシーバが受信するとメッセージは消える • レシーバが複数ある場合、どれか1つにしか届かない • イメージ メッセージ ※ 3つメッセージを送信しても、 メッセージ #1 それぞれ先に取得したレシーバにしか メッセージ #1 #1 届かない レシーバ メッセージ #3 センダ 宛先 メッセージ #2 送信 受信 受信 レシーバ2 メッセージ #1 受信 レシーバ3 2012/6/12 Beginning JavaEE6 勉強会(5) 31
  32. 32. 1.3.4.2 pub-subモデル • パブリッシュ・サブスクライブ・モデル – メッセージに対してレシーバが複数の場合使う • すべてのサブスクライバが受信するとメッセージは消える • P2Pモデルと違い、受信側は宛先に対して最初に 「購読(サブスクライブ)」作業をする必要がある (ただし明示的にメソッドコールする必要はない) • サブスクライバが「非アクティブ状態」だと無視される • イメージ メッセージ メッセージ #1 メッセージ #1 #1 サブスクライバ メッセージ メッセージ #1 パブリッシャ サブスクライブ 宛先 メッセージ #1 #1 パブリッシュ 受信 2012/6/12 Beginning JavaEE6 勉強会(5) 32
  33. 33. 1.3.4.2 pub-subモデル • パブリッシュ・サブスクライブ・モデル – メッセージに対してレシーバが複数の場合使う • すべてのサブスクライバが受信するとメッセージは消える • P2Pモデルと違い、受信側は宛先に対して最初に 「購読(サブスクライブ)」作業をする必要がある (ただし明示的にメソッドコールする必要はない) • サブスクライバが「非アクティブ状態」だと無視される • イメージ ※ すべて全サブスクライバに届く メッセージ サブスクライバ メッセージ メッセージ #1 メッセージ #1 メッセージ メッセージ #1 #1 #1 #1 パブリッシャ 宛先 サブスクライバ2 メッセージ パブリッシュ メッセージ #1 メッセージ #1 #1 2012/6/12 Beginning JavaEE6 勉強会(5) 33
  34. 34. 1.3.4.3 JMS API • JMS APIはjavax.jmsパッケージにある – クラス名だけだと他と被るので注意 http://java.sun.com/developer/technicalArticles/Ecommerce/jms/ 2012/6/12 Beginning JavaEE6 勉強会(5) 34
  35. 35. コネクション・ファクトリ • プロバイダと接続するための Connectionオブジェクトを作成する役割 Context jndiContext = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee6/ConnectionFactory"); org.beginningee6.book.chapter13.jms.ex01.Sender を参照 – JNDIルックアップで取得する – QueueConnectionFactory、TopicConnectionFacotry を使うと それぞれ専用の機能が利用できるようになる – 専用機能が不要の場合はConnectionFactoryでよい 2012/6/12 Beginning JavaEE6 勉強会(5) 35
  36. 36. 宛先(Destination) • プロバイダ情報を保持する。クライアントから プロバイダ情報を隠ぺいする役割 – クラス名は、「Queue」または「Topic」 – JNDIルックアップで取得する // Context jndiContext = new InitialContext(); // 前と同じ Queue queue = (Queue) jndiContext.lookup("jms/javaee6/Queue"); org.beginningee6.book.chapter13.jms.ex01.Sender を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 36
  37. 37. JNDIリソースをインジェクションで取得 • JNDIルックアップで取得するものは、 Java EE 6のコンテナ上で実行されるならば リソースインジェクションで取得することも可 // プライベート変数 @Resource(lookup = "jms/javaee6/ConnectionFactory") private static ConnectionFactory connectionFactory; @Resource(lookup = "jms/javaee6/Queue") private static Queue queue; org.beginningee6.book.chapter13.jms.ex04.Sender を参照 – いくつか要素があるが、lookupを覚えておけばOK – あとはAPIリファレンス参照 2012/6/12 Beginning JavaEE6 勉強会(5) 37
  38. 38. コネクション • JMSプロバイダとの接続を隠ぺいする役割 – スレッドセーフに設計されているため、 積極的に使いまわしすること Connection connection = connectionFactory.createConnection(); // いろいろ connection.start(); // メッセージの受信など connection.close(); // エラー処理は省略 org.beginningee6.book.chapter13.jms.ex01.Receiver を参照 ConnectionFactory. – 状態遷移図は右記の通り createConnection() – stopメソッドは受信の際に Connection. 一旦止めたい場合に利用する start() • connectionをクローズして Connection. 再生成するのはコストが高い stop() Connection. close() 2012/6/12 Beginning JavaEE6 勉強会(5) 38
  39. 39. セッション • メッセージ送信・受信時のグループ化の役割 – 1メッセージしか送らなくても作る必要がある – トランザクション機能により、一連のメッセージを、 すべて送るかすべて送らないかのいずれかにできる (アトミック性) – シングルスレッドで使うこと!(非スレッドセーフ) // Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // いろいろ // connection.start(); org.beginningee6.book.chapter13.jms.ex01.Receiver を参照 • 第一引数:トランザクション管理をする→true しない→false • 第二引数:メッセージ受信時の確認応答の仕方(後述). とりあえずAUTO_ACKNOWLEDGEでよい 2012/6/12 Beginning JavaEE6 勉強会(5) 39
  40. 40. メッセージ • 送受信したい情報を保持する役割 – ヘッダー、プロパティ、本文(Body)から構成される • ヘッダー:メッセージ識別、ルーティングに利用する情報 • プロパティ:アプリケーションから設定する付加情報 • 本文(Body):テキスト、バイト、オブジェクトなど。 プロパ ヘッダー 本文 ティ メッセージ – メッセージオブジェクト(Message)は、メッセージ・コ ンシューマのメソッドを利用して生成する(後述) 2012/6/12 Beginning JavaEE6 勉強会(5) 40
  41. 41. メッセージ:ヘッダー • メッセージ識別、ルーティングに利用する情報 – 各フィールドは、JMS仕様に規定されている フィールド 説明 設定方法 sendまたはpublishメソッ JMSDestination 宛先 ド sendまたはpublishメソッ JMSDeliveryMode 配信モード(損失防止の設定) ド sendまたはpublishメソッ JMSExpiration 有効期限 ド sendまたはpublishメソッ JMSPriority 優先度(0最低~9最高) ド sendまたはpublishメソッ JMSMessageID 一意に識別するためのID ド sendまたはpublishメソッ JMSTimestamp プロバイダに渡された時刻 ド JMSCorrelationID 関連するメッセージのリンク クライアント 2012/6/12 JMSReplyTo Beginning JavaEE6 勉強会(5) メッセージの応答の宛先 クライアント 41
  42. 42. メッセージ:プロパティ • アプリケーションから設定する付加情報、 ルーティングに利用する情報 – ヘッダとの違いはJMS仕様ではないこと • ヘッダのフィールドはJMS仕様で規定されている • 逆に、通信アプリ間では事前に合意しておく必要がある – アプリ固有の識別情報を本文の外に埋め込める • 後述する「セレクタ」で利用する // メッセージ送信前に設定する message.setIntProperty("orderAmount", 1); // 受信時(※ セレクタを利用する場合は設定で自動振り分けされる) int amount = message.getIntProperty("orderAmount"); org.beginningee6.book.chapter13.jms.ex07.Sender を参照 – データ型はプリミティブ型+String型が利用できる • 型ごとにメソッドが用意されている • 変換可能な型は、読み取り可能(詳細はJavadoc参照) 2012/6/12 Beginning JavaEE6 勉強会(5) 42
  43. 43. メッセージ:本文(Body) • テキスト、バイト、オブジェクトなど – メッセージのタイプ(型)は5種類 – それぞれのタイプに設定/取得メソッドが 用意されている インタフェース 説明 StreamMessage Javaプリミティブ型の値のストリームを扱う 名前と値のペアの組を扱う MapMessage 名前は文字列、値はJavaプリミティブ型 TextMessage 文字列を扱う シリアライズ可能なオブジェクト、 ObjectMessage あるいはシリアライズ可能なオブジェクトのコレクション を扱う BytesMessage バイトストリームを扱う 2012/6/12 Beginning JavaEE6 勉強会(5) 43
  44. 44. メッセージ・プロデューサ • メッセージ送信側のクライアント – Sessionから作成する – 別名:センダ(P2Pモデル)、 パブリッシャ(pub-subモデル) MessageProducer mp = session.createProducer(queue); mp.send(message); // QueueSender.send(message) // P2Pモデル用I/F 覚えなくてよし // TopicPublisher.publish(message) // pub-subモデル用I/F 覚えなくてよし • クライアントインタフェース(クラス)には、 モデルの違いはメソッド名が違うくらいで大差ない • 違いは、getQueue()/getTopic()メソッドを それぞれ持つだけ 2012/6/12 Beginning JavaEE6 勉強会(5) 44
  45. 45. メッセージの送信手順 • 送信側のソースが一通り読めるようになった ※ package文、import文、コメント等は紙面の都合で削除 public class Sender { public static void main(String[] args) { try { Context jndiContext = new InitialContext(); コネクションファクトリを ConnectionFactory connectionFactory ルックアップ = (ConnectionFactory) jndiContext.lookup("jms/javaee6/ConnectionFactory"); Queue queue = (Queue) jndiContext.lookup("jms/javaee6/Queue"); 宛先をルックアップ Connection connection = connectionFactory.createConnection(); コネクションを作成 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); セッションを作成 MessageProducer producer = session.createProducer(queue); クライアントを作成 TextMessage message = session.createTextMessage(); メッセージを作成 message.setText("This is a text message sent at " + new Date()); producer.send(message); メッセージを送信 System.out.println("nMessage sent !"); connection.close(); コネクションをクローズ } catch (Exception e) { e.printStackTrace(); } System.exit(0); } } org.beginningee6.book.chapter13.jms.ex01.Sender を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 45
  46. 46. メッセージ・コンシューマ • メッセージ受信側のクライアント – Sessionから作成する – 別名:レシーバ(P2Pモデル) サブスクライバ(pub-subモデル) MessageConsumer mc = session.createConsumer(queue); Connection.start(); TextMessage message = (TextMessage) mc.receive(); // QueueReceiver // P2Pモデル用I/F 覚えなくてよし // TopicSubscriber // pub-subモデル用I/F 覚えなくてよし • クライアントインタフェース(クラス)には、 モデルの違いはほとんどない • 違いは以下の通り。実用上、ほぼ使わないと思われる – getQueue()/getTopic()メソッドをそれぞれ持つこと – pub-subモデルには、NoLocal属性※のgetterがあること ※ 自分で配信したメッセージについて、自分が受信しないようにする設定 http://otndnld.oracle.co.jp/document/products/wls/docs92/jms/implement.html#wp1168490 2012/6/12 Beginning JavaEE6 勉強会(5) 46
  47. 47. メッセージの受信方法(同期・非同期) • 受信方法に、同期と非同期の方式を利用できる – 同期:receiveメソッドを呼び出す。 メッセージが到着するまでブロックする センダ 同期レシーバ 宛先 送信 取得 send() recieve() – 非同期:リスナを利用する。 イベントハンドラ(onMessage)を実装 センダ 登録 非同期レシーバ 宛先 通知 送信 send() 取得 2012/6/12 Beginning JavaEE6 勉強会(5) 47
  48. 48. 同期配信 • receive()を利用してメッセージを受信する – 着信を待つため処理をブロックしてしまう – 着信を待たないrecieveNoWait() もあるが、 ポーリングは自分で実装しなければならない public static void main(String[] args) { try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(topic); connection.start(); System.out.println("nInfinite loop. Waiting for a message..."); while (true) { TextMessage message = (TextMessage) consumer.receive(); System.out.println("Message received: " + message.getText()); } } catch (Exception e) { e.printStackTrace(); } } org.beginningee6.book.chapter13.jms.ex05.Receiver を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 48
  49. 49. 非同期配信 • リスナを使ったイベントモデルで実装できる public class Listener implements MessageListener { // … public static void main(String[] args) { System.out.println("nStarting listener...."); try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(topic); consumer.setMessageListener(new Listener()); // “Listener”は自クラスのクラス名 connection.start(); } catch (Exception e) { e.printStackTrace(); } } public void onMessage(Message message) { try { System.out.println("Message received: " + ((TextMessage) message).getText()); } catch (JMSException e) { e.printStackTrace(); } } } org.beginningee6.book.chapter13.jms.ex05.Listener を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 49
  50. 50. 13.4.4 セレクタ • 受信するメッセージをフィルタする場合に利用 – 主にpub-subモデルで利用する(と思われ) – ヘッダーとプロパティのどちらもフィルタに使える – 受信側作成時に設定するが送信側にも伝わっている • フィルタされるものは送信されないので帯域幅も節約 String selector = "orderAmount < 5 or orderAmount > 7"; // … MessageConsumer consumer = session.createConsumer(topic, selector); org.beginningee6.book.chapter13.jms.ex07.Receiver を参照 – 複合条件も可能 • 利用可能演算子 – NOT, AND, OR, =, >, >=, <, <=, <>, +, -, *, /, [NOT] BETWEEN, [NOT] IN, [NOT] LIKE, IS [NOT] NULL 2012/6/12 Beginning JavaEE6 勉強会(5) 50
  51. 51. 13.4.5 信頼性確保のメカニズム[1/2] • MOMにはメッセージを確実に送信するための 信頼性確保の機能が用意されている メカニズム 説明 メッセージ 古いメッセージの配信を制限する 有効期限 • producer.setTimeToLive(1000); • producer.send(msg, DeliveryMode.PERSISTENT, 2, 1000); メッセージ プロバイダのエラー時もメッセージが永続化されるようにする。 永続性の 「配信モード」で設定する。デフォルトは永続配信。 指定 • 1回配信する「永続配信」(DeliverMode.PERSISTENT) • 1回以上配信する「非永続配信」(DeliverMode.NON_PERSISTENT) 確認応答の メッセージ受信を確認応答する機能。トランザクション管理さ 制御 れている場合は自動。それ以外は確認応答モードを設定。 • connection.createSession(false, Session.AUTO_ACKNOWLEDGE); • 自動応答する場合:AUTO_ACKNOWLEDGE • 自動応答だが負荷を下げたい場合で、かつ重複受信してもよい場合: DUPS_OK_ACKNOWLEDGE – つづく • 明示的にクライアントがメソッドを呼ぶ場合:CLIENT_ACKNOWLEDGE (クライアント側でMessage.acknowledge()を呼ぶ) 2012/6/12 Beginning JavaEE6 勉強会(5) 51
  52. 52. 13.4.5 信頼性確保のメカニズム[2/2] (つづき) メカニズム 説明 恒久サブス サブスクライバが一時的にオフラインになっていても、 クライバの 再接続した時にオフライン中のメッセージを受信できる機能。 作成 (pub-subモデルでは通常オフライン中にメッセージ配信しない) topicConn = connFactory.createTopicConnection(); topicConn.setClientID(“client1”); session.createDurableSubscriber(topic, “name”); • 受信側だけで関係する • createDurableSubscriberの第二引数は恒久サブスクライバのID • 利用時はコネクションに毎回同じClient IDを設定すること • 購読を停止する際はSession.unsubscribe()メソッドをコールする 優先度の 緊急メッセージを優先配信できる機能。 設定 0最低から9最高まで指定可能。 • producer.setPriority(2); • producer.send(msg, DeliveryMode.PERSISTENT, 2, 1000) 2012/6/12 Beginning JavaEE6 勉強会(5) 52
  53. 53. Message Driven Bean 2012/6/12 Beginning JavaEE6 勉強会(5) 53
  54. 54. 13.5 メッセージ・ドリブンBean • EJBコンテナ上で実行されるアプリ向けの、 非同期メッセージングモデルを提供する仕組み – ここでの非同期とは、先で説明した配信方法では なく、メッセージングの特性のことを指している • メッセージが着信すると コンテナから呼び出される非同期コンシューマ – ここでの非同期とは、配信方法がブロックしない、とい う意味のほうを指している • コンテナ上の機能を利用できるため、 マルチスレッド化が容易 – コンテナがMDBインスタンスをプールし、メッセージが着 信するとインスタンスが割り当てられ、処理する – ただしステートレスにしなければならない 2012/6/12 Beginning JavaEE6 勉強会(5) 54
  55. 55. 13.5.1 MDBの作成方法 • 諸作業はコンテナが行うため、以下でよい @MessageDriven(mappedName = "jms/javaee6/Topic") public class BillingMDB08 implements MessageListener { public void onMessage(Message message) { TextMessage msg = (TextMessage) message; try { System.out.println("Message received: " + msg.getText()); } catch (JMSException e) { e.printStackTrace(); } } } org.beginningee6.book.chapter13.jms.ex08. BillingMDB08.java を参照 – @MessageDrivenアノテーションと、 javax.jms.MessageListenerを実装するのが重要 – JMSの設定を変える場合は実は少し面倒(後述) 2012/6/12 Beginning JavaEE6 勉強会(5) 55
  56. 56. 13.5.2 MDBモデル • MDBはWeb Profileに含まれないため、 EARファイルにしてデプロイする必要がある • MDBクラスの要件は以下の通り # 要件 1 @javax.ejb.MessageDrivenアノテーションを付与 またはXMLデプロイメントディスクリプタ内に同様の内容を定義 2 MessageListenerインタフェースを直接または間接的に実装 3 public、非final、非abstractクラスであること 4 引数なしパブリックコンストラクタがあること 5 finalizeメソッドが実装されていないこと 2012/6/12 Beginning JavaEE6 勉強会(5) 56
  57. 57. Work#2 MDBを動かす 1. (管理対象オブジェクトを作る)←実施済み 2. 受信側の用意 1. ビルドする(受信側) 2. デプロイする 3. 送信側の用意 1. ビルドする(送信側) 4. メッセージを送信しMDBを起動する 2012/6/12 Beginning JavaEE6 勉強会(4) 57
  58. 58. Work#2-2-1 ビルドする(受信側) • “Chapter 13 JMS(MDB)” プロジェクトを 「依存関係で構築」または 「生成物を削除して構築」 JMSプロジェクトと違い、 1回で全部ビルド&Jar化される 2012/6/12 Beginning JavaEE6 勉強会(5) 58
  59. 59. Work#2-2-2 デプロイする(コマンドライン) • Jarファイルをデプロイし、確認する > asadmin deploy chapter13-MDB-2.0.jar chapter13-MDB-2.0という名前のアプリケーションがデプロイされまし た。 コマンドdeployは正常に実行されました。 > asadmin" list-components chapter13-MDB-2.0 <ejb> ※1 C:Program Filesglassfish-3.1.2glassfishbinasadmin ※2 C:Users (ユーザ名) DocumentsNetBeansProjectsbook chapter13mdbtarget chapter13-MDB-2.0.jar 2012/6/12 Beginning JavaEE6 勉強会(5) 59
  60. 60. Work#2-3 ビルドする(送信側) • “Chapter 13 JMS(JMS)” プロジェクトを開く • pom.xmlを編集し、 適切なmainClassを指定してビルドする テキストメッセージ org.beginningee6.book.chapter13.jms.ex07. Sender DTOを利用したオブジェクトメッセージ org.beginningee6.book.chapter13.jms.ex14.OrderSender 2012/6/12 Beginning JavaEE6 勉強会(4) 60
  61. 61. Work#2-4 メッセージを送信しMDBを起動する • コマンドラインから送信側jarファイルを ACC上で起動する > appclient -client chapter13-JMS-2.0.jar ※1 C:Program Filesglassfish-3.1.2glassfishbinappclient ※2 C:Users (ユーザ名) DocumentsNetBeansProjectsbook chapter13jmstarget chapter13-JMS-2.0.jar – topicはシンプルメッセージを受け付ける topicに送信した場合は3つのMDBが起動する – queueはOrderDTOを受け付ける queueに送信した場合は1つのMDBが起動する 2012/6/12 Beginning JavaEE6 勉強会(4) 61
  62. 62. @MessageDrivenと@ActivationConfigProperty • @MessageDrivenアノテーションのフィールドと使い方 フィールド 説明 name Beanの名前 description 説明テキスト(デプロイツールが利用) mappedName 監視する宛先のJNDI名 Messagelistener インタフェースを複数実装した場合にMessageListenerInterfaceが Interface どれか指定する activationConfig 設定プロパティとその値のペアを@ActivationConfigPropertyアノ テーション配列で渡す。同アノテーションは propertyNameとpropertyValueというフィールドを持つ @MessageDriven(mappedName = "jms/javaee6/Topic", activationConfig = { @ActivationConfigProperty(propertyName = “acknowledgeMode”, propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "orderAmount < 3000") }) public class BillingMDB11 implements MessageListener { // … org.beginningee6.book.chapter13.jms.ex11. BillingMDB11.java を参照 2012/6/12 Beginning JavaEE6 勉強会(5) 62
  63. 63. 省略したところ • 依存性注入 – MDBにも別オブジェクトを注入できる。 当然なので省略 • MDBコンテキスト – トランザクションの状態や明示的ロールバック、 セキュリティの設定を知ることができる、 があまり利用しないと思われるので省略 • ライフサイクルと コールバック・アノテーション – ステートレス・セッションBeanと同じなので省略 2012/6/12 Beginning JavaEE6 勉強会(5) 63
  64. 64. 省略したところ2 • 13.5.2 コンシューマとしてのMDB – 同期受信しないでください、リソース無駄です、 という内容 • 13.5.3 プロデューサとしてのMDB – MDB内から別メッセージを送信することも可能、 という内容 – 送信時は、コネクションファクトリをMDBに @Resouceアノテーションで注入し、 onMessage内か委譲先でSessionを作成し メッセージを送信する、という内容 – 送信時は@MessageDrivenアノテーションは 関係ないので混乱しないように注意 2012/6/12 Beginning JavaEE6 勉強会(5) 64
  65. 65. 13.5.5 トランザクション • MDBはトランザクションを使用できる(BMT/CMT) – すべてのメッセージが送信されるか、 すべて送信されないか、の一貫性を保証する • 他のEJBと違いイベントドリブンモデルのため、 呼び出し元が居ない – トランザクションコンテキストが渡されてこない – そのためトランザクション属性は以下に限られる トランザクション属性 説明 REQUIRED MDBから他のEJBを呼び出す場合に、コンテナがト (デフォルト) ランザクションコンテキストを渡す。onMessageメ ソッド終了時にcommitされる。 NOT_SUPPORTED トランザクションコンテキストを渡さない。 – これらの属性は@javax.ejb.TransactionAttribute アノテーションで付与できる 2012/6/12 Beginning JavaEE6 勉強会(5) 65
  66. 66. 13.5.5 例外処理 • JMSの例外はJMSExceptionを継承している – 検査例外のためスローしてもロールバックしないの で注意 – ロールバックするには非検査例外をスローするか、 MessageDrivenContext.setRollBackOnly()を コールする • MessageDrivenContextはMDBに依存性注入すれば 得られる @Resource private MessageDrivenContext context; 2012/6/12 Beginning JavaEE6 勉強会(5) 66
  67. 67. まとめ 2012/6/12 Beginning JavaEE6 勉強会(5) 67
  68. 68. 13.7 まとめ • MOMを使うことで疎結合な非同期通信が可能 • JMS APIで利用できる – P2Pモデルとpub-subモデルを利用できる – コネクション・ファクトリ、宛先(QueueとTopic)、 コネクション、セッション、メッセージ等を利用 • EJBコンテナ上では、MDBを利用できる – メッセージ処理するコードが簡単に書ける 2012/6/12 Beginning JavaEE6 勉強会(5) 68

×