开发流程
JMS Queue 执行 load balancer语义:
一条消息仅能被一个 consumer(消费者) 收到。如果在 message 发送的时候没有可用的
consumer,那么它将被保存一直到能处理该 message 的 consumer 可用。如果一
个 consumer 收到一条 message 后却不响应它,那么这条消息将被转到另一个
consumer 那儿。一个 Queue 可以有很多 consumer,并且在多个可用的 consumer
中负载均衡。
注:
点对点消息传递域的特点如下:
• 每个消息只能有一个消费者。
• 消息的生产者和消费者之间没有时间上的相关性。无论消费者在生产者发
送消息的时候是否处于运行状态,它都可以提取消息。
Topic 实现 publish和 subscribe 语义:
一条消息被 publish时,它将发到所有感兴趣的订阅者,所以零到多个subscriber
将接收到消息的一个拷贝。但是在消息代理接收到消息时,只有激活订阅的
subscriber能够获得消息的一个拷贝。
注:
发布/订阅消息传递域的特点如下:
• 每个消息可以有多个消费者。
• 生产者和消费者之间有时间上的相关性。订阅一个主题的消费者只能消费
自它订阅之后发布的消息。JMS 规范允许客户创建持久订阅,这在一定程
度上放松了时间上的相关性要求。持久订阅允许消费者消费它在未处于激
活状态时发送的消息。
分别对应两种消息模式:
Point-to-Point (点对点),Publisher/Subscriber Model (发布/订阅者) 其中在 Publicher/Subscriber 模式下又有Nondurable subscription(非持久订阅)
和 durable subscription (持久化订阅)2种消息处理方式(支持离线消息)。
注:
在点对点消息传递域中,目的地被成为队列(queue);在发布/订阅消息传递
域中,目的地被成为主题(topic)。
Point-to-Point (点对点)消息模式开发流程
1、生产者(producer)开发流程(ProducerTool.java):
1.1 创建 Connection:
根据 url,user 和 password 创建一个 jms Connection。
Java代码
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
connection = connectionFactory.createConnection();
connection.start();
1.2 创建 Session:
在 connection的基础上创建一个 session,同时设置是否支持事务和
ACKNOWLEDGE 标识。
Java代码
Session session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
1.3 创建 Destination对象:
需指定其对应的主题(subject)名称,producer 和 consumer 将根据 subject
来发送/接收对应的消息。
Java代码
if (topic) {
destination = session.createTopic(subject);
} else {
destination = session.createQueue(subject);
}
1.4 创建 MessageProducer:
根据 Destination创建MessageProducer 对象,同时设置其持久模式。
Java代码
MessageProducer producer = session.createProducer(destination);
1.5 发送消息到队列(Queue):
封装 TextMessage 消息, 使用 MessageProducer 的 send 方法将消息发送出去。
Java代码
TextMessage message = session.createTextMessage(createMessageText(i));
producer.send(message);
2、消费者(consumer)开发流程(ConsumerTool.java):
2.1 实现 MessageListener 接口:
消费者类必须实现MessageListener 接口,然后在onMessage()方法中监听消息的
到达并处理。
Java代码
public class ConsumerTool extends Thread implements MessageListener, ExceptionListener
实现 onMessage(Message message)方法,实现监听消息的到达
2.2 创建 Connection:
根据 url,user 和 password 创建一个 jms Connection,如果是durable 模式,
还需要给 connection设置一个 clientId。
Java代码
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
Connection connection = connectionFactory.createConnection();
//是否是 durable 模式.(离线消息持久化支持)
if (durable && clientId != null && clientId.length() > 0 && !"null".equals(clientId)) {
connection.setClientID(clientId);
}
connection.setExceptionListener(this);
connection.start();
2.3 创建 Session 和 Destination:
与 ProducerTool.java 中的流程类似,不再赘述。
Java代码
session = connection.createSession(transacted, ackMode);
2.4 创建 replyProducer【可选】:
可以用来将消息处理结果发送给 producer。
2.5 创建 MessageConsumer:
根据 Destination创建MessageConsumer 对象。
Java代码
MessageConsumer consumer = null;
if (durable && topic) {
consumer = session.createDurableSubscriber((Topic) destination, consumerName);
} else {
consumer = session.createConsumer(destination);
}
2.6 消费 message:
在 onMessage()方法中接收producer 发送过来的消息进行处理,并可以通过
replyProducer 反馈信息给 producer
Java代码
if (message.getJMSReplyTo() != null) {
replyProducer.send(message.getJMSReplyTo()
, session.createTextMessage("Reply: "
+ message.getJMSMessageID()));
}
Publisher/Subscriber(发布/订阅者)消息模式开发流程
1、订阅者(Subscriber)开发流程(TopicListener.java):
1.1 实现 MessageListener 接口:
在 onMessage()方法中监听发布者发出的消息队列,并做相应处理。
Java代码
public void onMessage(Message message) {
if (checkText(message, "SHUTDOWN")) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace(System.out);
}
} else if (checkText(message, "REPORT")) {
// send a report:
try {
long time = System.currentTimeMillis() - start;
String msg = "Received " + count + " in " + time + "ms";
producer.send(session.createTextMessage(msg));
} catch (Exception e) {
e.printStackTrace(System.out);
}
count = 0;
} else {
if (count == 0) {
start = System.currentTimeMillis();
}
if (++count % 1000 == 0) {
System.out.println("Received " + count + " messages.");
}
}
}
1.2 创建 Connection:
根据 url,user 和 password 创建一个 jms Connection。
Java代码
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
connection = factory.createConnection();
1.3 创建 Session:
在 connection的基础上创建一个 session,同时设置是否支持事务和
ACKNOWLEDGE 标识。
Java代码
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
1.4 创建 Topic:
创建 2 个Topic, topictest.messages用于接收发布者发出的消息,
topictest.control用于向发布者发送消息,实现双方的交互。
Java代码
topic = session.createTopic("topictest.messages");
control = session.createTopic("topictest.control");
1.5 创建 consumer 和 producer 对象:
根据topictest.messages创建consumer,根据topictest.control创建producer。
Java代码
MessageConsumer consumer = session.createConsumer(topic);//创建消费者
consumer.setMessageListener(this);
connection.start();
producer = session.createProducer(control);//创建生产者
1.6 接收处理消息:
在 onMessage()方法中,对收到的消息进行处理,可直接简单在本地显示消
息,或者根据消息内容不同处理对应的业务逻辑(比如:数据库更新、文件操作
等等),并且可以使用 producer对象将处理结果返回给发布者。
Java代码
//可以先检查消息类型
ate static boolean checkText(Message m, String s) {
try {
return m instanceof TextMessage && ((TextMessage)m).getText().equals(s);
} catch (JMSException e) {
e.printStackTrace(System.out);
return false;
}
}
Java代码
//然后
if (checkText(message, "SHUTDOWN")) {
//关机
} else if (checkText(message, "REPORT")) {
// 打印
} else {
//别的操作
}
2、发布者(Publisher)开发流程(TopicPublisher.java):
2.1 实现 MessageListener 接口:
在 onMessage()方法中接收订阅者的反馈消息。
Java代码
public void onMessage(Message message) {
synchronized (mutex) {
System.out.println("Received report " + getReport(message) + " " + --remaining + " remaining");
if (remaining == 0) {
mutex.notify();
}
}
}
2.2 创建 Connection:
根据 url 创建一个 jms Connection。
Java代码
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
connection = factory.createConnection();
2.3 创建 Session:
在 connection的基础上创建一个 session,同时设置是否支持事务和
ACKNOWLEDGE 标识。
Java代码
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
2.4 创建 Topic:
创建 2 个Topic,topictest.messages用于向订阅者发布消息,topictest.control用
于接收订阅者反馈的消息。这2个topic与订阅者开发流程中的topic是一一对应
的。
Java代码
topic = session.createTopic("topictest.messages");
control = session.createTopic("topictest.control");
2.5 创建 consumer 和 producer 对象:
根据topictest.messages创建publisher;
根据topictest.control创建consumer,同时监听订阅者反馈的消息。
Java代码
publisher = session.createProducer(topic);
publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);//非持久化模式
session.createConsumer(control).setMessageListener(this);//加入监听
connection.start();
2.6 给所有订阅者发送消息,并接收反馈消息:
示例代码中,一共重复 10 轮操作。
Java代码
for (int i = 0; i < batch; i++) {
if (i > 0) {
Thread.sleep(delay * 1000);
}
times[i] = batch(messages);
System.out.println("Batch " + (i + 1) + " of " + batch + " completed in " + times[i] + " ms.");
}
每轮先向所有订阅者发送 2000 个消息;
Java代码
private long batch(int msgCount) throws Exception {
long start = System.currentTimeMillis();
remaining = subscribers;
publish();
waitForCompletion();
return System.currentTimeMillis() - start;
}
Java代码
private void publish() throws Exception {
// send events
BytesMessage msg = session.createBytesMessage();
msg.writeBytes(payload);
for (int i = 0; i < messages; i++) {
publisher.send(msg);
if ((i + 1) % 1000 == 0) {
System.out.println("Sent " + (i + 1) + " messages");
}
}
// request report
publisher.send(session.createTextMessage("REPORT"));
}
然后堵塞线程,开始等待;
Java代码
private void waitForCompletion() throws Exception {
System.out.println("Waiting for completion...");
synchronized (mutex) {
while (remaining > 0) {
mutex.wait();//赌赛线程
}
}
}
最后通过 onMessage()方法,接收到订阅者反馈的“REPORT”类信息后,才
print 反馈信息并解除线程堵塞,进入下一轮。
Java代码
public void onMessage(Message message) {
synchronized (mutex) {
System.out.println("Received report " + getReport(message) + " " + --remaining + " remaining");
if (remaining == 0) {
mutex.notify();//唤醒线程
}
}
}
注:可同时运行多个订阅者测试查看此模式效果
消息发送者能接受到消息接受者的信息,一直传递下去
package com.cn;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class TopicTest {
private String URL = "tcp://192.168.10.249:61616";
public static void main(String[] args) {
new TopicTest().start();
}
private void start() {
try {
ActiveMQConnectionFactory factory=new ActiveMQConnectionFactory(URL);
Connection connection;
connection = factory.createConnection();
connection.start();
//消息发送到这个Queue
Queue queue=new ActiveMQQueue("testQueue");
final Queue queue1=new ActiveMQQueue("queue");
//消息回复到这个Queue
Queue replyQueue=new ActiveMQQueue("replayQueue");
final Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Message message = session.createTextMessage("testQueue发送消息");
//希望消息接受者回复一条消息到replayQueue上面
message.setJMSReplyTo(replyQueue);
//消息发送者
MessageProducer messageProducer = session.createProducer(queue);
messageProducer.send(message);
//消息接受者
MessageConsumer messageConsumer = session.createConsumer(queue);
messageConsumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if(message instanceof TextMessage) {
TextMessage mes = (TextMessage)message;
try {
System.out.println(mes.getText());
MessageProducer messageProducer = session.createProducer(message.getJMSReplyTo());
Message message2 = session.createTextMessage("我有发回来了"+mes.getText());
message2.setJMSReplyTo(queue1);
messageProducer.send(message2);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
MessageConsumer consumer = session.createConsumer(replyQueue);
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if(message instanceof TextMessage) {
TextMessage mes = (TextMessage)message;
try {
System.out.println(mes.getText());
MessageProducer messageProducer = session.createProducer(message.getJMSReplyTo());
Message message2 = session.createTextMessage("我走了好几圈了"+mes.getText());
messageProducer.send(message2);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
MessageConsumer consumer1 = session.createConsumer(queue1);
consumer1.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if(message instanceof TextMessage) {
TextMessage mes = (TextMessage)message;
try {
System.out.println(mes.getText());
} catch (JMSException e) {
}
}
}
});
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
消息发送者
package com.cn;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JmsSender {
private String USER = ActiveMQConnection.DEFAULT_USER;
private String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
//private String URL = ActiveMQConnection.DEFAULT_BROKER_URL;
private String URL = “tcp://192.168.10.249:61616”;
private String SUBJECT = “ActiveMQ.Demo”;
private Destination destination = null;
private Connection conn = null;
private Session session = null;
private MessageProducer producer = null;
// 初始化
private void initialize() throws JMSException, Exception {
// 连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USER, PASSWORD, URL);
conn = connectionFactory.createConnection();
// 事务性会话,自动确认消息
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 消息的目的地(Queue/Topic)
//destination = session.createQueue(SUBJECT);
destination = session.createTopic(SUBJECT);
// 消息的提供者(生产者)
producer = session.createProducer(destination);
// 不持久化消息
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
public void sendMessage(String msgType) throws JMSException, Exception {
initialize();
// 连接到JMS提供者(服务器)
conn.start();
// 发送文本消息
if ("text".equals(msgType)) {
String textMsg = "ActiveMQ Text Message!";
TextMessage msg = session.createTextMessage();
// TextMessage msg = session.createTextMessage(textMsg);
msg.setText(textMsg);
producer.send(msg);
}
// 发送Map消息
if ("map".equals(msgType)) {
MapMessage msg = session.createMapMessage();
msg.setBoolean("boolean", true);
msg.setShort("short", (short) 0);
msg.setLong("long", 123456);
msg.setString("MapMessage", "ActiveMQ Map Message!");
producer.send(msg);
}
// 发送流消息
if ("stream".equals(msgType)) {
String streamValue = "ActiveMQ stream Message!";
StreamMessage msg = session.createStreamMessage();
msg.writeString(streamValue);
msg.writeBoolean(false);
msg.writeLong(1234567890);
producer.send(msg);
}
// 发送对象消息
if ("object".equals(msgType)) {
JmsObjectMessageBean jmsObject = new JmsObjectMessageBean("ActiveMQ Object Message", 18, false);
ObjectMessage msg = session.createObjectMessage();
msg.setObject(jmsObject);
producer.send(msg);
}
// 发送字节消息
if ("bytes".equals(msgType)) {
String byteValue = "字节消息";
BytesMessage msg = session.createBytesMessage();
msg.writeBytes(byteValue.getBytes());
producer.send(msg);
}
}
// 关闭连接
public void close() throws JMSException {
if (producer != null)
producer.close();
if (session != null)
session.close();
if (conn != null)
conn.close();
}
}
消息接受者
package com.cn;
import java.util.Enumeration;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JmsReceiver implements MessageListener{
private String USER = ActiveMQConnection.DEFAULT_USER;
private String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
//private String URL = ActiveMQConnection.DEFAULT_BROKER_URL;
private String URL = “tcp://192.168.10.249:61616”;
private String SUBJECT = “ActiveMQ.Demo”;
private Destination destination = null;
private Connection conn = null;
private Session session = null;
private MessageConsumer consumer = null;
private boolean stop = false;
// 初始化
private void initialize() throws JMSException, Exception {
// 连接工厂是用户创建连接的对象.
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USER, PASSWORD, URL);
// 连接工厂创建一个jms connection
conn = connectionFactory.createConnection();
conn.setClientID("");
// 是生产和消费的一个单线程上下文。会话用于创建消息的生产者,消费者和消息。会话提供了一个事务性的上下文。
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); // 不支持事务
// 目的地是客户用来指定他生产消息的目标还有他消费消息的来源的对象.
//destination = session.createQueue(SUBJECT);
destination = session.createTopic(SUBJECT);
// 会话创建消息的生产者将消息发送到目的地
consumer = session.createConsumer(destination);
session.createDurableSubscriber((Topic) destination, "");
}
public void receiveMessage() throws JMSException, Exception {
initialize();
conn.start();
consumer.setMessageListener(this);
// 等待接收消息
while (!stop) {
Thread.sleep(5000);
}
}
@Override
public void onMessage(Message msg) {
try {
if (msg instanceof TextMessage) {
TextMessage message = (TextMessage) msg;
System.out.println("------Received TextMessage------");
System.out.println(message.getText());
} else if (msg instanceof MapMessage) {
MapMessage message = (MapMessage) msg;
System.out.println("------Received MapMessage------");
System.out.println(message.getLong("long"));
System.out.println(message.getBoolean("boolean"));
System.out.println(message.getShort("short"));
System.out.println(message.getString("MapMessage"));
System.out.println("------Received MapMessage for while------");
Enumeration enumer = message.getMapNames();
while (enumer.hasMoreElements()) {
Object obj = enumer.nextElement();
System.out.println(message.getObject(obj.toString()));
}
} else if (msg instanceof StreamMessage) {
StreamMessage message = (StreamMessage) msg;
System.out.println("------Received StreamMessage------");
System.out.println(message.readString());
System.out.println(message.readBoolean());
System.out.println(message.readLong());
} else if (msg instanceof ObjectMessage) {
System.out.println("------Received ObjectMessage------");
ObjectMessage message = (ObjectMessage) msg;
JmsObjectMessageBean jmsObject = (JmsObjectMessageBean) message.getObject();
System.out.println(jmsObject.getUserName() + "__" + jmsObject.getAge() + "__" + jmsObject.isFlag());
} else if (msg instanceof BytesMessage) {
System.out.println("------Received BytesMessage------");
BytesMessage message = (BytesMessage) msg;
byte[] byteContent = new byte[1024];
int length = -1;
StringBuffer content = new StringBuffer();
while ((length = message.readBytes(byteContent)) != -1) {
content.append(new String(byteContent, 0, length));
}
System.out.println(content.toString());
} else {
System.out.println(msg);
}
stop = true;
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
this.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
// 关闭连接
public void close() throws JMSException {
System.out.println("Consumer:->Closing connection");
if (consumer != null)
consumer.close();
if (session != null)
session.close();
if (conn != null)
conn.close();
}
}