JMS基本的な概念や規範
メッセージングドメイン(JMSドメイン)
また、メッセージモード、メッセージのモデルとして知られている、2種類があります。
- ピア(P2P)
コンセプト
- メッセージキュー(待ち行列)
- プロバイダ(送信者)
- 消費者(レシーバー)
- 各メッセージは、特定のキューに送信され、受信機は、キューからメッセージを取得します。それは彼らが消費またはタイムアウトするまで、メッセージキューを保持します。
機能
- 各メッセージには、唯一の消費者(コンシューマー)(すなわち、消費たら、メッセージがメッセージキューになくなりました)です
- プロバイダーと消費者の間の時間に依存しない、プロバイダがメッセージを送信するときに消費者が何も実行されていないかどうか、それはメッセージがキューに送信されます影響しません、と言うことです
- 各メッセージは、消費者に送信されます。そこキューリスニングで複数の消費者かもしれませんが、キュー内の各メッセージは、コンシューマ・キューによって消費することができます。
- メッセージ内の順序があります。キューメッセージサーバキューへのメッセージの順序に応じて消費者に送信します。消費者がされている場合は、キューの先頭から(メッセージの優先順位がない限り)それらを削除します。
- 成功するためにメッセージキューを受信することに成功した消費者の反応の後
2.パブリッシュおよびサブスクライブ(パブ/サブ)
コンセプト
- テーマ(トピック)
- パブリッシャー(出版社)
- 加入者(加入者)
機能
- 各メッセージには、複数のコンシューマを持つことができます
- パブリッシャとサブスクライバの間の時間に依存してあります。トピックの加入後は、それが消費者に加入者、出版社のメッセージを作成する必要がありますし、メッセージを消費するために、加入者は、実行中の状態を維持しなければなりません。
- そのような厳密な時間相関を緩和するために、JMSは、加入者が永続的なサブスクリプションを作成することができます。このように、加入者が実行されていない場合でも、それはまた、メッセージのパブリッシャを受け取ることができます。
- 各メッセージには、複数のメッセージコンシューマと呼ばれる加入者に送信されます。
- 出版社は通常、加入者がメッセージのトピックを受信しているところのは意味わかりません。
- メッセージが要求することなく、消費者に送信されることを意味し、消費者にプッシュメッセージ。
組成メッセージ(データフォーマット)
1.メッセージ・ヘッダ
メッセージは、識別情報とルーティング情報を含んでいます
2.消息体
-
TextMessage - Stringオブジェクト
-
MapMessage - 名前のセット - 値のペア
-
BytesMessageは - データ・ストリームの1つのバイト
-
StreamMessageの - フローデータのJavaの元の値
-
ObjectMessage - シリアル化されたJavaオブジェクト
配置详解:
从上可知:p2p模型和发布订阅(pub/sub)有个很大的区别就是时间上的依赖性的区别。p2p默认不依赖时间,而发布订阅需要创建一个可持久化的订阅。发布订阅模型默认自带了kahaDB 存储方式 (官方推荐。基于日志文件,5.4 之后的默认持久化)。无需配置。但是为了方便查看,这边改用jdbc来持久化订阅。下面提一下配置(linux上安装)。
第一步:引入3个jar包:
mysql(数据库驱动) 、HikariCP(连接池) 、slf4j(日志接口) , 放到 activemq安装目录下的lib文件夹下;
第二步:安装目录activemq/conf/activemq.xml 配置 dataSource
<!-- Hikari Datasource -->
<bean id="activemq-mysql" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://192.168.5.4:3306/activemq?serverTimezone=GMT%2B8"/>
<property name="username" value="root" />
<property name="password" value="1234" />
</bean>
配置持久化
<persistenceAdapter>
<!--默认配置 <kahaDB directory="${activemq.data}/kahadb"/> -->
<jdbcPersistenceAdapter dataSource="#activemq-mysql" createTablesOnStartup="true"/></persistenceAdapter>
第三步:先建好数据库(库名同上jdbc配置),再重启activeMQ;
第四步:成功,自动建表如下:
ACTIVEMQ_ ACKS : 存储持久订阅的信息
ACTIVEMQ_ LOCK : 锁表(集群使用)
ACTIVEMQ_ MSGS : 消息表
三个表详解:
activemq_acks:
用于存储订阅关系,如果是持久化的Topic,订阅者和服务器订阅关系在这个表保:主要的数据库字段如下
container:消息的Destination
sub_dest:如果是使用的Static集群,这个字段会有集群和其他系统的信息
client_id:订阅者都必须有一个唯一的客户端id用于区分
sub_name:订阅者名称
selector:选择器,可以选择只消费满足条件的消息,条件可以用自定义属性实现,可以支持多属性and和or操作
last_acked_id:记录消费过的消息id
activemq_lock
在集群环境中才有用,只有一个broker可以获得消息,称为Master Broker,其他的只能作为备份等待
activemq_msg:
メッセージを格納するために、Queneおよびトピックは、このテーブルに格納されている:
IDデータベース自動増分基本キー
コンテナを:宛先メッセージ
msgid_prod:送信側クライアント・メッセージ主キー
msg_seqは:注文メッセージであるメッセージIDされ、msgid_prod + msg_seqは、JMSから構成されてもよいです
有効期限:メッセージの有効期限、ミリ秒1970-01-01の数格納する
メッセージ:Javaのバイナリデータ列オブジェクトメッセージボディ
prioritry:0-9からの優先権、より大きな優先度の高いデータを
最後に、テストコードを添付:
瓶包
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.11</version>
</dependency>
接続設定
public class MyConfig {
//定义ActiveMQ的连接地址
public static final String ACTIVEMQ_URL = "tcp://192.168.5.4:61616";
//topic 队列名称
public static final String TOPIC_NAME = "topic_01";
}
出版社
public class PersistentSender {
public static void main(String[] args) throws JMSException {
//创建连接工厂
ConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory(MyConfig.ACTIVEMQ_URL);
//创建连接
Connection connection = activeMQConnectionFactory.createConnection();
//打开连接
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列目标
Destination destination = session.createTopic(MyConfig.TOPIC_NAME);
//创建一个生产者
MessageProducer producer = session.createProducer(destination);
//发送消息时用使用持久模式(默认的,可写可不写)
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
//创建消息
TextMessage message = session.createTextMessage("我是永恒的帅哥擦擦擦");
//发送消息
producer.send(message);
//在本地打印消息
System.out.println("我现在发的消息是:" + message.getText());
//关闭连接
connection.close();
}
}
受信者
public class PersistentRecv01 {
public static void main(String[] args) throws JMSException {
String myId = "PersistentRecv01";
//创建连接工厂
ConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory(MyConfig.ACTIVEMQ_URL);
//创建连接
Connection connection = activeMQConnectionFactory.createConnection();
//持久订阅
connection.setClientID(myId);
//打开连接
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列目标
Topic topic = session.createTopic(MyConfig.TOPIC_NAME);
//创建消费者
MessageConsumer consumer = session.createDurableSubscriber(topic, myId);
//接收消息(这里也可以用while循环)
//textMessage = (TextMessage)consumer.receive(); 是一个阻塞队列
//这里用监听器持续接收消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
TextMessage receive = (TextMessage)message;
try {
System.out.println("PersistentRecv 111 : " + receive.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
}
}