ActiveMQ主题(Topic)模式下消息生产与消费
消息生产者
package service.topic;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
public class TopicProducer {
/**
* ActiveMq服务器地址
* 支持的协议参见官网 http://activemq.apache.org/configuring-transports
* TCP协议使用文档 http://activemq.apache.org/tcp-transport-reference
*/
public static final String DEFAULT_BROKER_URL = "tcp://192.168.136.135:61616";
public static final String USER_NAME = "admin";
public static final String PWD = "admin";
public static final String TOPIC_NAME = "test.topic";
public void work() {
try {
// 1. Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USER_NAME, PWD, DEFAULT_BROKER_URL);
// 2. Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
// 3. Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4.Create the destination (Topic or Queue)
Destination destination = session.createTopic(TOPIC_NAME);
// 5. Create a MessageProducer from the Session to the Topic or Queue 创建消息生产者
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 6. Create a messages 创建消息
String text = System.currentTimeMillis() + "Hello world! From: " + Thread.currentThread().getName();
TextMessage message = session.createTextMessage(text);
// Tell the producer to send the message 生产者发送消息
System.out.println("Sent message: " + text);
producer.send(message);
// Clean up
session.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
消息消费者
package service.topic;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
public class TopicConsumer implements Runnable {
/**
* ActiveMq服务器地址
* 支持的协议参见官网 http://activemq.apache.org/configuring-transports
* TCP协议使用文档 http://activemq.apache.org/tcp-transport-reference
*/
public static final String DEFAULT_BROKER_URL = "tcp://192.168.136.135:61616";
public static final String USER_NAME = "admin";
public static final String PWD = "admin";
public static final String TOPIC_NAME = "test.topic";
public static void main(String[] args) {
}
public void run() {
try {
// 1. Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USER_NAME, PWD, DEFAULT_BROKER_URL);
// 2. Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
connection.setExceptionListener(new ExceptionListener() {
public void onException(JMSException e) {
System.out.println("JMS Exception occured. Shutting down client.");
}
});
// 3. Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4.Create the destination (Topic or Queue)
Destination destination = session.createTopic(TOPIC_NAME);
// 5. Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
final String currentThreadName = Thread.currentThread().getName();
// 6. Wait for a message
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = null;
try {
text = textMessage.getText();
} catch (JMSException e) {
e.printStackTrace();
}
System.out.println(currentThreadName + " Received: " + text);
} else {
System.out.println(currentThreadName + " Received: " + message);
}
}
});
// 阻塞线程,使消息消费完后才关闭连接
System.in.read();
consumer.close();
session.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试:
package service.topic;
public class TopicTest {
public static void main(String[] args) {
//主题模式下需要先启动消费者
for (int i = 0; i < 3; i++) {
Thread topicThread = new Thread(new TopicConsumer());
topicThread.setName("第" + i + "个消费者");
topicThread.start();
}
new TopicProducer().work();
}
}
Sent message: 1614507988736Hello world! From: main
第1个消费者 Received: 1614507988736Hello world! From: main
第0个消费者 Received: 1614507988736Hello world! From: main
第2个消费者 Received: 1614507988736Hello world! From: main
由此可见,生产者生产了一条消息,三个消费者均消费到了此消息。
topic,queue模式比较:
比较项 | Topic模式 | Queue模式 |
---|---|---|
工作模式 | “订阅发布模式”,如果没有订阅者,消息会被丢弃,如有多个订阅者,那么多个订阅者都会受到消息 | “负载均衡”模式,如果没有消费者,消息也不会丢弃,如果有多个消费者,消息只会被其中一个消费者消费 |
有无状态 | 无 | Queue数据会以文件形式在mq服务器上保存,也可配置数据库存储 |
传递完整性 | 如果没有订阅者,消息会被丢弃 | 消息不会被丢弃 |
处理效率 | 消息按照订阅者数量进行复制,订阅者越多处理效率越低,不同消息协议间也会有差异 | 一条消息只会被一个消费者消费,消费者再多性能也不会明显降低,不同消息协议间也会有差异 |