beginning java ee 6 勉強会(5) #bje_study

68
Beginning JavaEE6 勉勉勉 (5) - 勉勉勉勉勉勉勉 - Jun. 13, 2012

Upload: zuisener

Post on 11-Jun-2015

3.142 views

Category:

Education


2 download

TRANSCRIPT

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

Beginning JavaEE6 勉強会 (5)- メッセージ通信 -

Jun. 13, 2012

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

2

目次

04/13/2023 Beginning JavaEE6 勉強会 (5)

13. メッセージ通信

メッセージング

JMS

MDB

@ 見たな

ggrks

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

3

メッセージング

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

4

メッセージ指向ミドルウェア

• メッセージング処理– 異種システム間対応可能– 非同期通信

• メッセージ指向ミドルウェア (MOM)– 上記処理を可能にするソフトウェア– 通信内容(メッセージ)の生成・消費ペースを

調整するバッファとして機能する– メッセージの形式と「宛先」について合意する

だけで疎結合なシステム連携が実現できる• RPC (Remote Procedure Call) の場合、

メソッドシグネチャまで合意しなければならない

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

5

メッセージの流れ

13.1 メッセージとは

• MOM の用語

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先

メッセージプロバイダ

(別名:ブローカ)

コンシューマプロデューサ

メッセージ

受信送信

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

6

メッセージの流れ

13.1 メッセージとは

• MOM の用語

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先

メッセージプロバイダ

(別名:ブローカ)

コンシューマプロデューサ

メッセージ

受信送信メッセージの格納場所メッセージプロバイダ内に複数作れる

メッセージを溜め、振り分けるソフトウェア

メッセージを受けて処理するコンポーネント

メッセージを他のコンポーネントに送信するコンポーネント

連携データ

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

7

13.1 メッセージとは

• JMS (Java Message Service)– メッセージの処理を Java アプリケーションから行

うための API– JDBC が複数データベース製品に対応するように、

JMS も製品を抽象化し複数製品に対応できる

• メッセージ・ドリブン Bean(MDB)– メッセージを受けて起動したい処理があるとき、

EJB コンテナにメッセージの定期的な監視と受信を任せることができる仕組み

– ステートレス . メッセージ間で独立して起動– 実際の処理はステートレス Bean に移譲してもよい

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

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 )

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

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 が参照実装としてオープンソース化

– 2012 JMS 2.0 仕様公開予定( JSR 343 )04/13/2023 Beginning JavaEE6 勉強会 (5)

書籍外

ポイント10 年間仕様変更

なし

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

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/matrix04/13/2023 Beginning JavaEE6 勉強会 (5)

書籍外

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

11

13.3 メッセージを送受信する方法

• 以下の簡単なモデルで JMS だけを試す– 作成するのは Sender と Receiver クラスだけ– 他は設定と API を呼ぶのみ

04/13/2023 Beginning JavaEE6 勉強会 (5)

メッセージの流れ

OpenMQNetBeans 同梱の

Glassfish サーバに同梱されている

ReceiverSender

メッセージ

受信送信Queuemain() main()

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

12

Work#1 メッセージを送信する

作業手順1. MOM を起動する2. MOM に「管理対象オブジェクト」を作る

1. 宛先を作る2. コネクションファクトリを作る

3. Java でプロデューサ (Sender.java) を作る4. Java でコンシューマ (Receiver.java) を作る5. ビルド6. 動かす

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

13

Work#1-1 MOM を起動する

• Glassfish に付属している OpenMQ を使うので、単に Glassfish を起動する

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

14

Work#1-2 管理対象オブジェクトを作る

• ブラウザで OpenMQ の管理コンソールを開く– http://localhost:4848/

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

15

Work#1-2-1 コネクションファクトリを作る

• コネクションファクトリを作る– 下記 3 つだけ埋めてあとはデフォルトでよし

04/13/2023 Beginning JavaEE6 勉強会 (5)

jms/javaee6/ConnectionFactoryjavax.jms.ConnectionFactoryjms/javaee6/ConnectionFactory

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

16

Work#1-2-2 宛先を作る

• 宛先を作る。( Work#1 では” Queue” を作る)– 下記 4 つだけ埋めてあとはデフォルトでよし

04/13/2023 Beginning JavaEE6 勉強会 (5)

jms/javaee6/Queuejms_javaee6_Queuejavax.jms.Queuejms/javaee6/Queue

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

17

Work#1-3 プロデューサを作る

• メッセージプロデューサ(生成側)– https://svn.kenai.com/svn/beginningee6~src/book/trunk/ を checkout– “Chapter 13 - JMS (JMS)” プロジェクト– “org.beginningee6.book.chapter13.jms.ex01” パッケージ

04/13/2023 Beginning JavaEE6 勉強会 (5)

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); }}

※ package 文、 import 文、コメント等は紙面の都合で削除

org.beginningee6.book.chapter13.jms.ex01.Sender を参照

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

18

Work#1-4 コンシューマを作る

• メッセージコンシューマ(消費側)– プロデューサと同様

04/13/2023 Beginning JavaEE6 勉強会 (5)

public class Receiver {

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(); } }

}

※ package 文、 import 文、コメント等は紙面の都合で削除

org.beginningee6.book.chapter13.jms.ex01.Receiver を参照

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

19

Work#1-5-1 ビルド -mainClass 指定

• pom.xml を編集し、動かしたいクラスを<mainClass> に指定

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

20

Work#1-5-2 ビルド - 実行

• 「依存関係で構築」または「生成物を削除して構築」

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

21

Work#1-5 動かす(コマンドライン)

• プロバイダを起動する(数回)– テキストメッセージが宛先に 1 つ送られる

• コンシューマを起動する( mainClass 変えて生成する)– 送ったメッセージがすべて表示される

04/13/2023 Beginning JavaEE6 勉強会 (5)

> appclient -client chapter13-JMS-2.0.jar

※1 C:\Program Files\glassfish-3.1.2\glassfish\bin\appclient※2 C:\Users\ (ユーザ名) \Documents\NetBeansProjects\book\    chapter13\jms\target \chapter13-JMS-2.0.jar

> appclient -client chapter13-JMS-2.0.jar※ デフォルトでは生成物名が同じなので注意

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

22

補足 1 : JMS リソースをコマンドラインから操作• JMS リソースはコマンドラインから操作可能– 実は設定項目がわかっていればそちらの方が簡単– コマンドは Glassfish に添付されている

• C:\Program Files\glassfish-3.1.2\glassfish\bin\asadmin

04/13/2023 Beginning JavaEE6 勉強会 (5)

asadmin create-jms-resource --restype javax.jms.ConnectionFactory jms/javaee6/ConnectionFactoryasadmin create-jms-resource --restype javax.jms.QueueConnectionFactory jms/javaee6/QConnectionFactoryasadmin create-jms-resource --restype javax.jms.TopicConnectionFactory jms/javaee6/TConnectionFactoryasadmin create-jms-resource --restype javax.jms.Queue jms/javaee6/Queueasadmin create-jms-resource --restype javax.jms.Topic jms/javaee6/Topic

asadmin list-jms-resources

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

23

補足 2 :スタンドアロン JMS クライアント• Work#1 はコンテナ外からでも動かせる– この場合ライブラリを読み込む必要があるので注意

• 金魚本では ACC 上で動かすようになっている– スタンドアロンの Glassfish インストールフォルダ

に同梱されているライブラリを使う。

– 必要なファイルは以下の通りインストールフォルダは人によって異なる• C:\Program Files\glassfish-3.1.2\mq\lib\jms.jar• C:\Program Files\glassfish-3.1.2\mq\lib\jms.jar• C:\Program Files\glassfish-3.1.2\glassfish\lib\gf-client.jar

04/13/2023 Beginning JavaEE6 勉強会 (5)

今回は面倒なので省略

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

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 動作確認時の送信側スタブとして使う

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

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 の例。今回は利用しない。(時間がない)

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

26

Java Message Service

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

27

13.4 Java Message Service

• 構成

04/13/2023 Beginning JavaEE6 勉強会 (5)

JMS プロバイダ

JNDI ディレクトリ

プロデューサ コンシューマ

メッセージの生成 メッセージの使用

管理対象オブジェクトのルックアップ

管理対象オブジェクトのルックアップ

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

28

13.4 Java Message Service

• 構成

04/13/2023 Beginning JavaEE6 勉強会 (5)

JMS プロバイダ

JNDI ディレクトリ

プロデューサ コンシューマ

メッセージの生成 メッセージの使用

管理対象オブジェクトのルックアップ

管理対象オブジェクトのルックアップ

クライアント

メッセージを送受信するアプリ。「クライアント」と総称する。・送信側は、プロデューサ、センダ、

 パブリッシャと呼ぶ。・受信側は、コンシューマ、 レシーバ、サブスクライバと呼ぶ。

MOM のこと。別名:ブローカメッセージのバッファや配信を制御

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

29

13.4 Java Message Service

• 用語– JMS の世界では 2 つのモデルがあり、 API が違う

– 宛先( Destination )={ Queue, Topic}– P2P モデル → Queue– pub-sub モデル → Topic

04/13/2023 Beginning JavaEE6 勉強会 (5)

一般名 ポイント・ツー・ポイント パブリッシュ・サブスクライブ

Destination Queue TopicConnectionFactory QueueConnectionFactory TopicConnectionFactoryConnection QueueConnection TopicConnectionSession QueueSession TopicSessionMessageConsumer QueueReciever TopicRecieverMessageProducer QueueSender TopicSender

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

30

1.3.4.1 P2P モデル

• ポイント・ツー・ポイント・モデル– メッセージに対してレシーバが 1 つの場合使う

• レシーバが受信するとメッセージは消える• レシーバが複数ある場合、どれか 1 つにしか届かない

• イメージ

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先レシーバ

センダ

メッセージ#1

受信送信

メッセージ#1メッセージ

#1

メッセージ#1メッセージ

#1メッセージ#1

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

31

1.3.4.1 P2P モデル

• ポイント・ツー・ポイント・モデル– メッセージに対してレシーバが 1 つの場合使う

• レシーバが受信するとメッセージは消える• レシーバが複数ある場合、どれか 1 つにしか届かない

• イメージ

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先レシーバ

センダ受信送信

レシーバ 2受信

レシーバ 3

受信

メッセージ#1メッセージ

#1メッセージ#1

メッセージ#3 メッセージ

#2

メッセージ#1

※ 3 つメッセージを送信しても、  それぞれ先に取得したレシーバにしか  届かない

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

32

1.3.4.2 pub-sub モデル

• パブリッシュ・サブスクライブ・モデル– メッセージに対してレシーバが複数の場合使う

• すべてのサブスクライバが受信するとメッセージは消える

• P2P モデルと違い、受信側は宛先に対して最初に「購読(サブスクライブ)」作業をする必要がある(ただし明示的にメソッドコールする必要はない)

• サブスクライバが「非アクティブ状態」だと無視される

• イメージ

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先サブスクライバ

パブリッシャ

メッセージ#1

サブスクライブ

パブリッシュ

メッセージ#1メッセージ

#1

メッセージ#1メッセージ

#1メッセージ#1

受信

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

33

1.3.4.2 pub-sub モデル

• パブリッシュ・サブスクライブ・モデル– メッセージに対してレシーバが複数の場合使う

• すべてのサブスクライバが受信するとメッセージは消える

• P2P モデルと違い、受信側は宛先に対して最初に「購読(サブスクライブ)」作業をする必要がある(ただし明示的にメソッドコールする必要はない)

• サブスクライバが「非アクティブ状態」だと無視される

• イメージ

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先

サブスクライバ

パブリッシャ

メッセージ#1

サブスクライブ

パブリッシュ

メッセージ#1メッセージ

#1

メッセージ#1メッセージ

#1メッセージ#1

受信

サブスクライバ2サブスクライブメッセージ

#1メッセージ#1メッセージ

#1受信

※ すべて全サブスクライバに届く

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

34

1.3.4.3 JMS API

• JMS API は javax.jms パッケージにある– クラス名だけだと他と被るので注意

04/13/2023 Beginning JavaEE6 勉強会 (5)

http://java.sun.com/developer/technicalArticles/Ecommerce/jms/

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

35

コネクション・ファクトリ

• プロバイダと接続するためのConnection オブジェクトを作成する役割

– JNDI ルックアップで取得する– QueueConnectionFactory 、 TopicConnectionF

acotry を使うとそれぞれ専用の機能が利用できるようになる

– 専用機能が不要の場合は ConnectionFactory でよい

04/13/2023 Beginning JavaEE6 勉強会 (5)

Context jndiContext = new InitialContext();

ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee6/ConnectionFactory");

org.beginningee6.book.chapter13.jms.ex01.Sender を参照

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

36

宛先 (Destination)

• プロバイダ情報を保持する。クライアントからプロバイダ情報を隠ぺいする役割– クラス名は、「 Queue 」または「 Topic 」– JNDI ルックアップで取得する

04/13/2023 Beginning JavaEE6 勉強会 (5)

// Context jndiContext = new InitialContext(); // 前と同じ

Queue queue = (Queue) jndiContext.lookup("jms/javaee6/Queue");org.beginningee6.book.chapter13.jms.ex01.Sender を

参照

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

37

JNDI リソースをインジェクションで取得

• JNDI ルックアップで取得するものは、Java EE 6 のコンテナ上で実行されるならばリソースインジェクションで取得することも可

– いくつか要素があるが、 lookup を覚えておけばOK

– あとは API リファレンス参照04/13/2023 Beginning JavaEE6 勉強会 (5)

// プライベート変数@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 を参照

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

38

コネクション

• JMS プロバイダとの接続を隠ぺいする役割– スレッドセーフに設計されているため、積極的に使いまわしすること

– 状態遷移図は右記の通り– stop メソッドは受信の際に一旦止めたい場合に利用する• connection をクローズして再生成するのはコストが高い

04/13/2023 Beginning JavaEE6 勉強会 (5)

Connection connection = connectionFactory.createConnection();// いろいろconnection.start();// メッセージの受信などconnection.close();// エラー処理は省略

ConnectionFactory.createConnection()

Connection.close()

Connection.start()

Connection.stop()

org.beginningee6.book.chapter13.jms.ex01.Receiver を参照

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

39

セッション• メッセージ送信・受信時のグループ化の役割

– 1 メッセージしか送らなくても作る必要がある– トランザクション機能により、一連のメッセージを、

すべて送るかすべて送らないかのいずれかにできる(アトミック性)

– シングルスレッドで使うこと!(非スレッドセーフ)

• 第一引数:トランザクション管理をする→ true     しない→ false

• 第二引数:メッセージ受信時の確認応答の仕方(後述) .     とりあえず AUTO_ACKNOWLEDGE でよい

04/13/2023 Beginning JavaEE6 勉強会 (5)

// Connection connection = connectionFactory.createConnection();Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// いろいろ// connection.start(); org.beginningee6.book.chapter13.jms.ex01.Receiver を参照

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

40

メッセージ• 送受信したい情報を保持する役割

– ヘッダー、プロパティ、本文( Body )から構成される• ヘッダー:メッセージ識別、ルーティングに利用する情報• プロパティ:アプリケーションから設定する付加情報• 本文( Body ):テキスト、バイト、オブジェクトなど。

– メッセージオブジェクト( Message )は、メッセージ・コンシューマのメソッドを利用して生成する(後述)

04/13/2023 Beginning JavaEE6 勉強会 (5)

ヘッダー プロパティ 本文

メッセージ

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

41

メッセージ:ヘッダー

• メッセージ識別、ルーティングに利用する情報– 各フィールドは、 JMS 仕様に規定されている

04/13/2023 Beginning JavaEE6 勉強会 (5)

フィールド 説明 設定方法

JMSDestination 宛先 send または publish メソッド

JMSDeliveryMode 配信モード(損失防止の設定) send または publish メソッド

JMSExpiration 有効期限 send または publish メソッド

JMSPriority 優先度( 0 最低~ 9 最高 ) send または publish メソッド

JMSMessageID 一意に識別するための ID send または publish メソッド

JMSTimestamp プロバイダに渡された時刻 send または publish メソッド

JMSCorrelationID 関連するメッセージのリンク クライアントJMSReplyTo メッセージの応答の宛先 クライアント

JMSType メッセージタイプ(後述)の識別子

クライアント

JMSRedelivered 再配信メッセージか否か JMS プロバイダ

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

42

メッセージ:プロパティ• アプリケーションから設定する付加情報、

ルーティングに利用する情報– ヘッダとの違いは JMS 仕様ではないこと

• ヘッダのフィールドは JMS 仕様で規定されている• 逆に、通信アプリ間では事前に合意しておく必要がある

– アプリ固有の識別情報を本文の外に埋め込める• 後述する「セレクタ」で利用する

– データ型はプリミティブ型+ String型が利用できる• 型ごとにメソッドが用意されている• 変換可能な型は、読み取り可能(詳細は Javadoc 参照)

04/13/2023 Beginning JavaEE6 勉強会 (5)

// メッセージ送信前に設定するmessage.setIntProperty("orderAmount", 1);// 受信時(※ セレクタを利用する場合は設定で自動振り分けされる)int amount = message.getIntProperty("orderAmount");

org.beginningee6.book.chapter13.jms.ex07.Sender を参照

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

43

メッセージ:本文( Body )

• テキスト、バイト、オブジェクトなど– メッセージのタイプ(型)は 5 種類– それぞれのタイプに設定 /取得メソッドが

用意されている

04/13/2023 Beginning JavaEE6 勉強会 (5)

インタフェース 説明StreamMessage Java プリミティブ型の値のストリームを扱う

MapMessage 名前と値のペアの組を扱う名前は文字列、値は Java プリミティブ型

TextMessage 文字列を扱う

ObjectMessageシリアライズ可能なオブジェクト、あるいはシリアライズ可能なオブジェクトのコレクションを扱う

BytesMessage バイトストリームを扱う

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

44

メッセージ・プロデューサ

• メッセージ送信側のクライアント– Session から作成する– 別名:センダ( P2P モデル)、

   パブリッシャ( pub-sub モデル)

• クライアントインタフェース(クラス)には、モデルの違いはメソッド名が違うくらいで大差ない

• 違いは、 getQueue()/getTopic() メソッドをそれぞれ持つだけ

04/13/2023 Beginning JavaEE6 勉強会 (5)

MessageProducer mp = session.createProducer(queue);mp.send(message);

// QueueSender.send(message) // P2P モデル用 I/F 覚えなくてよし// TopicPublisher.publish(message) // pub-sub モデル用 I/F 覚えなくてよし

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

45

メッセージの送信手順

• 送信側のソースが一通り読めるようになった

04/13/2023 Beginning JavaEE6 勉強会 (5)

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); }}

※ package 文、 import 文、コメント等は紙面の都合で削除

コネクションファクトリをルックアップ

宛先をルックアップ

コネクションを作成

セッションを作成

クライアントを作成

メッセージを作成

メッセージを送信

コネクションをクローズ

org.beginningee6.book.chapter13.jms.ex01.Sender を参照

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

46

メッセージ・コンシューマ• メッセージ受信側のクライアント

– Session から作成する– 別名:レシーバ( P2P モデル)

   サブスクライバ( pub-sub モデル)

• クライアントインタフェース(クラス)には、モデルの違いはほとんどない

• 違いは以下の通り。実用上、ほぼ使わないと思われる– getQueue()/getTopic() メソッドをそれぞれ持つこと– pub-sub モデルには、 NoLocal 属性※の getter があること

04/13/2023 Beginning JavaEE6 勉強会 (5)

MessageConsumer mc = session.createConsumer(queue);Connection.start();TextMessage message = (TextMessage) mc.receive();

// QueueReceiver // P2P モデル用 I/F 覚えなくてよし// TopicSubscriber // pub-sub モデル用 I/F 覚えなくてよし

※ 自分で配信したメッセージについて、自分が受信しないようにする設定   http://otndnld.oracle.co.jp/document/products/wls/docs92/jms/implement.html#wp1168490

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

47

メッセージの受信方法(同期・非同期)

• 受信方法に、同期と非同期の方式を利用できる– 同期: receive メソッドを呼び出す。

   メッセージが到着するまでブロックする

– 非同期:リスナを利用する。    イベントハンドラ( onMessage )を実装

04/13/2023 Beginning JavaEE6 勉強会 (5)

宛先同期レシーバセンダ

取得recieve()

送信send()

宛先非同期レシーバセンダ 登録

送信send()

通知

取得

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

48

同期配信

• receive() を利用してメッセージを受信する– 着信を待つため処理をブロックしてしまう– 着信を待たない recieveNoWait() もあるが、

ポーリングは自分で実装しなければならない

04/13/2023 Beginning JavaEE6 勉強会 (5)

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 を参照

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

49

非同期配信

• リスナを使ったイベントモデルで実装できる

04/13/2023 Beginning JavaEE6 勉強会 (5)

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 を参照

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

50

13.4.4 セレクタ

• 受信するメッセージをフィルタする場合に利用– 主に pub-sub モデルで利用する(と思われ)– ヘッダーとプロパティのどちらもフィルタに使える– 受信側作成時に設定するが送信側にも伝わっている

• フィルタされるものは送信されないので帯域幅も節約

– 複合条件も可能• 利用可能演算子

– NOT, AND, OR, =, >, >=, <, <=, <>, +, -, *, /, [NOT] BETWEEN, [NOT] IN, [NOT] LIKE,IS [NOT] NULL

04/13/2023 Beginning JavaEE6 勉強会 (5)

String selector = "orderAmount < 5 or orderAmount > 7";// …MessageConsumer consumer = session.createConsumer(topic, selector);

org.beginningee6.book.chapter13.jms.ex07.Receiver を参照

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

51

13.4.5 信頼性確保のメカニズム [1/2]

• MOM にはメッセージを確実に送信するための信頼性確保の機能が用意されている

– つづく

04/13/2023 Beginning JavaEE6 勉強会 (5)

メカニズム 説明

メッセージ有効期限

古いメッセージの配信を制限する• 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() を呼ぶ)

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

52

13.4.5 信頼性確保のメカニズム [2/2](つづき)

04/13/2023 Beginning JavaEE6 勉強会 (5)

メカニズム 説明

恒久サブスクライバの作成

サブスクライバが一時的にオフラインになっていても、再接続した時にオフライン中のメッセージを受信できる機能。( 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)

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

53

Message Driven Bean

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

54

13.5 メッセージ・ドリブン Bean

• EJB コンテナ上で実行されるアプリ向けの、非同期メッセージングモデルを提供する仕組み– ここでの非同期とは、先で説明した配信方法では

なく、メッセージングの特性のことを指している

• メッセージが着信するとコンテナから呼び出される非同期コンシューマ– ここでの非同期とは、配信方法がブロックしない、という

意味のほうを指している

• コンテナ上の機能を利用できるため、マルチスレッド化が容易– コンテナが MDB インスタンスをプールし、メッセージが着信するとインスタンスが割り当てられ、処理する

– ただしステートレスにしなければならない04/13/2023 Beginning JavaEE6 勉強会 (5)

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

55

13.5.1 MDB の作成方法

• 諸作業はコンテナが行うため、以下でよい

– @MessageDriven アノテーションと、javax.jms.MessageListener を実装するのが重要

– JMS の設定を変える場合は実は少し面倒(後述)04/13/2023 Beginning JavaEE6 勉強会 (5)

@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 を参照

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

56

13.5.2 MDB モデル

• MDB は Web Profile に含まれないため、EAR ファイルにしてデプロイする必要がある

• MDB クラスの要件は以下の通り

04/13/2023 Beginning JavaEE6 勉強会 (5)

# 要件

1 @javax.ejb.MessageDriven アノテーションを付与または XML デプロイメントディスクリプタ内に同様の内容を定義

2 MessageListener インタフェースを直接または間接的に実装

3 public 、非 final 、非 abstract クラスであること

4 引数なしパブリックコンストラクタがあること

5 finalize メソッドが実装されていないこと

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

57

Work#2 MDB を動かす

1. (管理対象オブジェクトを作る)←実施済み2. 受信側の用意

1. ビルドする(受信側)2. デプロイする

3. 送信側の用意1. ビルドする(送信側)

4. メッセージを送信し MDB を起動する

04/13/2023 Beginning JavaEE6 勉強会 (4)

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

58

Work#2-2-1 ビルドする(受信側)

• “Chapter 13 JMS(MDB)” プロジェクトを「依存関係で構築」または「生成物を削除して構築」

04/13/2023 Beginning JavaEE6 勉強会 (5)

JMS プロジェクトと違い、1回で全部ビルド& Jar 化される

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

59

Work#2-2-2 デプロイする(コマンドライン)• Jar ファイルをデプロイし、確認する

04/13/2023 Beginning JavaEE6 勉強会 (5)

> asadmin deploy chapter13-MDB-2.0.jarchapter13-MDB-2.0 という名前のアプリケーションがデプロイされました。コマンド deploy は正常に実行されました。 > asadmin" list-componentschapter13-MDB-2.0 <ejb>

※1 C:\Program Files\glassfish-3.1.2\glassfish\bin\asadmin※2 C:\Users\ (ユーザ名) \Documents\NetBeansProjects\book\    chapter13\mdb\target \chapter13-MDB-2.0.jar

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

60

Work#2-3 ビルドする(送信側)• “Chapter 13 JMS(JMS)” プロジェクトを開く• pom.xml を編集し、 適切な mainClass を指定してビルドする

04/13/2023 Beginning JavaEE6 勉強会 (4)

テキストメッセージ  org.beginningee6.book.chapter13.jms.ex07. SenderDTO を利用したオブジェクトメッセージ  org.beginningee6.book.chapter13.jms.ex14.OrderSender

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

61

Work#2-4 メッセージを送信し MDB を起動する• コマンドラインから送信側 jar ファイルを

ACC 上で起動する

– topic はシンプルメッセージを受け付けるtopic に送信した場合は 3 つの MDB が起動する

– queue は OrderDTO を受け付けるqueue に送信した場合は 1 つの MDB が起動する

04/13/2023 Beginning JavaEE6 勉強会 (4)

> appclient -client chapter13-JMS-2.0.jar

※1 C:\Program Files\glassfish-3.1.2\glassfish\bin\appclient※2 C:\Users\ (ユーザ名) \Documents\NetBeansProjects\book\    chapter13\jms\target \chapter13-JMS-2.0.jar

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

62

@MessageDriven と@ActivationConfigProperty• @MessageDriven アノテーションのフィールドと使い方

04/13/2023 Beginning JavaEE6 勉強会 (5)

フィールド 説明

name Bean の名前

description 説明テキスト(デプロイツールが利用)

mappedName 監視する宛先の JNDI 名

MessagelistenerInterface

インタフェースを複数実装した場合にMessageListenerInterface がどれか指定する

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 を参照

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

63

省略したところ

• 依存性注入– MDB にも別オブジェクトを注入できる。当然なので省略

• MDB コンテキスト– トランザクションの状態や明示的ロールバック、

セキュリティの設定を知ることができる、があまり利用しないと思われるので省略

• ライフサイクルとコールバック・アノテーション– ステートレス・セッション Bean と同じなので省略

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

64

省略したところ2

• 13.5.2 コンシューマとしての MDB– 同期受信しないでください、リソース無駄です、

という内容• 13.5.3 プロデューサとしての MDB– MDB 内から別メッセージを送信することも可能、

という内容– 送信時は、コネクションファクトリを MDB に

@Resouce アノテーションで注入し、onMessage 内か委譲先で Session を作成しメッセージを送信する、という内容

– 送信時は @MessageDriven アノテーションは関係ないので混乱しないように注意

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

65

13.5.5 トランザクション

• MDB はトランザクションを使用できる( BMT/CMT )– すべてのメッセージが送信されるか、

すべて送信されないか、の一貫性を保証する• 他の EJB と違いイベントドリブンモデルのため、

呼び出し元が居ない– トランザクションコンテキストが渡されてこない– そのためトランザクション属性は以下に限られる

– これらの属性は @javax.ejb.TransactionAttributeアノテーションで付与できる

04/13/2023 Beginning JavaEE6 勉強会 (5)

トランザクション属性 説明

REQUIRED( デフォルト )

MDB から他の EJB を呼び出す場合に、コンテナがトランザクションコンテキストを渡す。 onMessage メソッド終了時に commit される。

NOT_SUPPORTED トランザクションコンテキストを渡さない。

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

66

13.5.5 例外処理

• JMS の例外は JMSException を継承している– 検査例外のためスローしてもロールバックしないの

で注意– ロールバックするには非検査例外をスローするか、

MessageDrivenContext.setRollBackOnly() をコールする• MessageDrivenContext は MDB に依存性注入すれば得られる

04/13/2023 Beginning JavaEE6 勉強会 (5)

@Resource private MessageDrivenContext context;

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

67

まとめ

04/13/2023 Beginning JavaEE6 勉強会 (5)

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

68

13.7 まとめ

• MOM を使うことで疎結合な非同期通信が可能• JMS API で利用できる– P2P モデルと pub-sub モデルを利用できる– コネクション・ファクトリ、宛先 (Queue と

Topic) 、コネクション、セッション、メッセージ等を利用

• EJB コンテナ上では、 MDB を利用できる– メッセージ処理するコードが簡単に書ける

04/13/2023 Beginning JavaEE6 勉強会 (5)