公司做智能硬件的,使用ActiveMQ做消息队列,我接手这块,学习了一下,记点笔记,供大家参考
一、ActiveMQ简介
ActiveMQ,名字上看是一种MessageQueue,其实是支持Queue(队列)和Topic(广播)两种模式。
他本身是一种异步的处理机制,所以主要的应用场景主要是对大应用解耦合,做异步处理,他所支持的mqtt协议还可以用作移动端与服务器的通讯处理。
ActiveMQ是支持JMS规范的,我们知道JMS有两种消息模型(Point-to-Point(点对点)和Publish/Subscribe Message(消息广播)),虽然他们的父类都可以实现Queue和Topic,但是基于规范,建议基于p2p模型实现Queue模式,基于Pub/Sub实现Topic。
二、Queue消息
Queue是点对点的消息模型,一个Sender虽然可以有多个Receiver,但是Sender发出的消息只会由一个并且是保证有且只有一个Receiver接收,接收后mq会收到通知把这条消息删除,如果暂时没有Receiver,Queue默认在mq服务器上以文件形式保存,直到有一个Receiver连线接收。
1.Queue发送
// 创建链接工厂
QueueConnectionFactory factory = new ActiveMQConnectionFactory(null, null, "tcp://127.0.0.1:61616");
// 通过工厂创建一个连接
connection = factory.createQueueConnection();
// 启动连接
connection.start();
// 创建一个session会话
session = connection.createQueueSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);//①
// 创建一个消息队列
Queue queue = session.createQueue("test.queue");
// 创建消息发送者
javax.jms.QueueSender sender = session.createSender(queue);
// 设置持久化模式
sender.setDeliveryMode(DeliveryMode.PERSISTENT);//②
MapMessage map = session.createMapMessage();
map.setString("text", message);
sender.send(map);
// 提交会话
session.commit();
2.Queue接收
// 创建链接工厂
QueueConnectionFactory factory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://127.0.0.1:61616");
// 通过工厂创建一个连接
connection = factory.createQueueConnection();
// 启动连接
connection.start();
// 创建一个session会话
session = connection.createQueueSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);//①
// 创建一个消息队列
Queue queue = session.createQueue("test.queue");
// 创建消息制作者
javax.jms.QueueReceiver receiver = session.createReceiver(queue);
receiver.setMessageListener(new MessageListener() {
public void onMessage(Message msg) {
if (msg != null) {
MapMessage map = (MapMessage) msg;
try {
System.out.println(map.getLong("time") + "接收#" + map.getString("text"));
msg.acknowledge();//③
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
// 提交会话
session.commit();
①connection.createQueueSession(A, B):
如果A为true,为支持事务,则B只能为SESSION_TRANSACTED,这种情况下,在事务开启之后,和session.commit()之前,所有消费的消息,要么全部正常确认,要么全部redelivery,由于Session是共享的,使用此种方式时,需要对每一个请求创建新的session,以为造成业务处理错误;
如果A为false,则不支持事务则,B可以为AUTO_ACKNOWLEDGE、CLIENT_ACKNOWLEDGE或DUPS_OK_ACKNOWLEDGE。AUTO_ACKNOWLEDGE为自动确认(择机确认具有不确定性);CLIENT_ACKNOWLEDGE为客户端手动确认,如Queue接收实例中的③,该确认有两种方式,message.acknowledge()将当前session中所有consumer中尚未ACK的消息都一起确认,而ActiveMQMessageConsumer.acknowledege()只会对当前consumer中那些尚未确认的消息进行确认;DUPS_OK_ACKNOWLEDGE只对Topic消息起作用,当consumer故障重启后,那些尚未被MQ确认的消息会重新发送过来;
②queue消息未被消费或者手动清除的情况下是会保存的,在P2P类型中当DeliveryMode设置为NON_PERSISTENCE时,消息被保存在内存中,而当DeliveryMode设置为PERSISTENCE时,消息保存在broker的相应的文件或者数据库中。而且P2P中消息一旦被Consumer消费就从broker中删除。
若MessageListener是异步模式,B不能为SESSION_TRANSACTED。
三、Topic消息
Topic是Publish-Subscribe-Message的消息模型,数据是无状态不落地的,所以publisher发出的每条消息不能保证subscriber都能收到,只有监听该publisher的subscriber才能收到,如果没有customer在监听,该消息就相当于消失了,Topic是一对多的,所有监听publisher的subscriber都可以收到消息。
1.Topic发送
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(null, null, "failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)");//①
TopicConnection connection = factory.createTopicConnection();
connection.start();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
TopicPublisher producer = session.createPublisher(new ActiveMQTopic("test.topic"));
TextMessage message = session.createTextMessage();
message.setText("message_" + System.currentTimeMillis());
producer.send(message);
session.commit();
2.Topic接收
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)");
TopicConnection connection = factory.createTopicConnection();
connection.start();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("test.topic");
TopicSubscriber consumer = session.createSubscriber(topic);
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
ActiveMQBytesMessage tm = (ActiveMQBytesMessage) message;
System.out.println("Received message: " + tm.getMessage());
}
});
session.commit();
①ActiveMQ支持断线重连
后记:先写到这儿,写一写对自己来说也收获颇多,下一篇涉及到mqtt的内容