简介
在前面一篇文章里讨论过几种应用系统集成的方式,发现实际上面向消息队列的集成方案算是一个总体比较合理的选择。这里,我们先针对具体的一个消息队列Activemq的基本通信方式进行探讨。activemq是JMS消息通信规范的一个实现。总的来说,消息规范里面定义最常见的几种消息通信模式主要有发布-订阅、点对点这两种。另外,通过结合这些模式的具体应用,我们在处理某些应用场景的时候也衍生出来了一种请求应答的模式。下面,我们针对这几种方式一一讨论一下。
基础流程
在讨论具体方式的时候,我们先看看使用activemq需要启动服务的主要过程。
按照JMS的规范,我们首先需要获得一个JMS connection factory.,通过这个connection factory来创建connection.在这个基础之上我们再创建session, destination, producer和consumer。因此主要的几个步骤如下:
1. 获得JMS connection factory. 通过我们提供特定环境的连接信息来构造factory。
2. 利用factory构造JMS connection
3. 启动connection
4. 通过connection创建JMS session.
5. 指定JMS destination.
6. 创建JMS producer或者创建JMS message并提供destination.
7. 创建JMS consumer或注册JMS message listener.
8. 发送和接收JMS message.
9. 关闭所有JMS资源,包括connection, session, producer, consumer等。
publish-subscribe
发布订阅模式有点类似于我们日常生活中订阅报纸。每年到年尾的时候,邮局就会发一本报纸集合让我们来选择订阅哪一个。在这个表里头列了所有出版发行的报纸,那么对于我们每一个订阅者来说,我们可以选择一份或者多份报纸。比如北京日报、潇湘晨报等。那么这些个我们订阅的报纸,就相当于发布订阅模式里的topic。有很多个人订阅报纸,也有人可能和我订阅了相同的报纸。那么,在这里,相当于我们在同一个topic里注册了。对于一份报纸发行方来说,它和所有的订阅者就构成了一个1对多的关系。这种关系如下图所示:
现在,假定我们用前面讨论的场景来写一个简单的示例。我们首先需要定义的是publisher.
消息主体
消息主体包含了消息的核心数据。
JMS 定义了5中消息类型: TextMessage、MapMessage、BytesMessage、
StreamMessage和ObjectMessage
选择最合适的消息类型可以使JMS最有效 的处理消息。
-
TextMessage(文本消息)
将数据作为简单字符串存放在主体中(XML就可以作为字符串发)
TextMessage msg = session.createTextMessage();
msg.setText(text);
有些厂商支持一种XML专用的消息格式,带来了便利,但是不是标准的JMS类型,影响
移植性。
只自己定义了两个方法setText(String s)、getText()
-
MapMessage(映射消息)
使用一张映射表来存放其主体内容(参照Jms API)
MapMessage msg = session.createMapMessage();
msg.setString(“CUSTOMER_NAME”,”John”);
msg.setInt(“CUSTOMER_AGE”,12);
String s = msg.getString(“CUSTOMER_NAME”);
int age = msg.getInt(“CUSTOMER_AGE”);
-
BytesMessage(字节消息)
将字节流存放在消息主体中。适合于下列情况:必须压缩发送的大量数据、需要与现有
消息格式保持一致等(参照Jms API)
byte[] data;
BytesMessage msg = session.createBytesMessage();
msg.wirte(data);
byte[] msgData = new byte[256];
int bytesRead = msg.readBytes(msgData);
-
StreamMessage(流消息)
用于处理原语类型。这里也支持属性字段和MapMessage所支持的数据类型。使用这种
消息格式时,收发双方事先协商好字段的顺序,以保证写读顺序相同(参照Jms API)
StringMessage msg = session.createStreamMessage();
msg.writeString(“John”);
msg.writeInt(12);
String s = msg.readString();
Int age = msg.readInt();
(PS:个人认为有点像socket的信息收发)
-
ObjectMessage(对象消息)
用于往消息中写入可序列化的对象。
消息中可以存放一个对象,如果要存放多个对象,需要建立一个对象集合,然后把这个
集合写入消息。
客户端接收到一个ObjectMessage时,是read-only模式。如果一个客户端试图写
message,将会抛出MessageNotWriteableException。如果调用了clearBody方法,message既可以读又可以写
自己只单独定义了两个方法:getObject()和setObject(Serializable s)
ObjectMessage包含的只是object的一个快照,set之后object的修改对ObjectMessage的body无效 (从两个方法可以看出,这种消息已经强制要你实现Java.io. Serializable接口)
Message只读时被set抛出MessageNotWriteableException;
set和get时,如果对象序列化失败抛出MessageFormatException