回顾
点对点
Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费,不可重复消费。
简单例子
依赖
注意版本对应
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.15.9</version>
</dependency>
同步方式接收消息
使用同步方式接收消息的话,消息订阅者调用receive()方法。在receive()中,消息未到达或在到达指定时间之前,方法会阻塞,直到消息可用。
生产者
代码:
package com.example.queue.同步;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@SuppressWarnings("all")
public class ProducerDemo {
public void sendMessage(String msg) {
// 连接工厂
ConnectionFactory factory = null;
// 连接对象
Connection connection = null;
// 目的地
Destination destination = null;
// 会话
Session session = null;
// 消息发送者
MessageProducer producer = null;
// 消息对象
Message message = null;
try {
// 创建连接ActiveMQ服务的连接工厂
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://127.0.0.1:61616");
// 通过工厂,创建连接对象
connection = factory.createConnection();
// 消息的发送者可以不启动连接(建议启动连接),消息的消费者必须启动连接
// producer在发送消息的时候,会检查是否启动了连接。如果未启动,则自动启动
// 如果没有特殊的配置,建议配置完毕后再启动连接
connection.start();
/*
* 通过连接对象,创建会话对象,必须绑定目的地
*
* transacted:是否支持事务
* true:支持事务,第二个参数默认无效,建议传递的数据是Session.SESSION_TRANSACTED
* false:不支持事务,常用参数,第二个参数必须传递,且必须有效
*
* acknowledgeMode:如何确认消息的处理,使用确认机制实现
* AUTO_ACKNOWLEDGE:自动确认消息,消息的消费者处理消息后,自动确认
* CLIENT_ACKNOWLEDGE:客户端手动确认,消息的消费者处理消息后,必须手动确认
* DUPS_OK_ACKNOWLEDGE:有副本的客户端手动确认。一个消息可以多次处理;可以降低Session的消耗,在可以容忍重复消息时使用(不推荐使用)
*/
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
// 创建目的地。参数是目的地名称(唯一标识)
destination = session.createQueue("hello");
// 通过会话对象,创建消息的发送者
// 创建producer的时候,可以不提供目的地,而在发送消息的时候指定目的地
producer = session.createProducer(destination);
// 创建文本消息
message = session.createTextMessage(msg);
// 使用producer,发送消息到目的地
producer.send(message);
System.out.println("消息已发送");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 回收资源
// 回收消息发送者
if (producer!=null) {
try {
producer.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收会话对象
if (session!=null) {
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收连接对象
if (connection!=null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ProducerDemo demo = new ProducerDemo();
demo.sendMessage("hello world");
}
}
输出:
消息已发送
Queues:
消费者
代码:
package com.example.queue.同步;
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;
@SuppressWarnings("all")
public class ConsumerDemo {
public String receiveTextMessage() {
String returnMsg = "";
// 连接工厂
ConnectionFactory factory = null;
// 连接对象
Connection connection = null;
// 目的地
Destination destination = null;
// 会话
Session session = null;
// 消息消费者,用于接收消息的对象
MessageConsumer consumer = null;
// 消息对象
Message message = null;
try {
// 创建连接ActiveMQ服务的连接工厂
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://127.0.0.1:61616");
// 通过工厂,创建连接对象
connection = factory.createConnection();
// 消息的消费者必须启动连接,否则无法处理消息
connection.start();
// 通过连接对象,创建会话对象,必须绑定目的地
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建目的地。参数是目的地名称(唯一标识)
destination = session.createQueue("hello");
// 创建消息消费者对象,在指定目的地中获取消息
consumer = session.createConsumer(destination);
// 获取队列中的消息
// receive方法是一个主动获取消息的方法。执行一次,拉取一个消息,开发少用
message = consumer.receive();
// 处理文本消息
returnMsg = ((TextMessage)message).getText();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 回收资源
// 回收消息消费者
if (consumer!=null) {
try {
consumer.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收会话对象
if (session!=null) {
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收连接对象
if (connection!=null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
return returnMsg;
}
public static void main(String[] args) {
ConsumerDemo demo = new ConsumerDemo();
String returnMsg = demo.receiveTextMessage();
System.out.println(returnMsg);
}
}
输出:
hello world
Queues:
异步方式接收消息
使用异步方式接收消息的话,消息订阅者需注册一个消息监听者,类似于事件监听器,只要消息到达,JMS服务提供者会通过调用监听器的onMessage()递送消息。
先创建一个消费者
代码:
package com.example.queue.异步;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@SuppressWarnings("all")
public class ConsumerDemo {
public void consumMessage() {
// 连接工厂
ConnectionFactory factory = null;
// 连接对象
Connection connection = null;
// 目的地
Destination destination = null;
// 会话
Session session = null;
// 消息消费者,用于接收消息的对象
MessageConsumer consumer = null;
try {
// 创建连接ActiveMQ服务的连接工厂
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://127.0.0.1:61616");
// 通过工厂,创建连接对象
connection = factory.createConnection();
// 消息的消费者必须启动连接,否则无法处理消息
connection.start();
// 通过连接对象,创建会话对象,必须绑定目的地
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
// 创建目的地。参数是目的地名称(唯一标识)
destination = session.createQueue("hello");
// 创建消息消费者对象,在指定目的地中获取消息
consumer = session.createConsumer(destination);
// 注册监听器。注册成功后,队列中的消息变化会自动触发监听器代码。接收消息并处理
consumer.setMessageListener(new MessageListener() {
/*
* 监听器一旦注册,永久有效(consumer线程不关闭)
* 处理消息的方式:只要有消息未处理,自动调用onMessage方法处理消息
* 监听器可以注册若干个,注册多个监听器,类似于集群
* ActiveMQ自动循环调用多个监听器,处理队列中的消息,实现并行处理
*
* 处理消息的方法,就是监听方法
* 监听的事件是:消息、消息未处理
* 要处理的具体内容:消息处理
* 参数message:未处理的消息
*/
@Override
public void onMessage(Message message) {
try {
// 确认方法,代表consumer已经收到消息。确认后,MQ删除对应的消息
message.acknowledge();
String data = ((TextMessage) message).getText();
System.out.println(data);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
// 阻塞当前代码
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 回收资源
// 回收消息消费者
if (consumer != null) {
try {
consumer.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收会话对象
if (session != null) {
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
// 回收连接对象
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ConsumerDemo demo = new ConsumerDemo();
demo.consumMessage();
}
}
发送消息
在代码里或者mq面板发送一条消息
发送消息代码跟上面同步方式相同
IDE内输出:
hello world
测试是否可以重复消费
启动多个实例
发送一条消息
只有一个收到了消息