概述
RabbitMQ是一个开源的消息代理和队列服务器, 用来通过普通协议在完全不同的应用之间共享数据, RabbitMQ使用Erlang语言来编写的, 并且RabbitMQ是基于AMQP协议的
优点
- 开源, 性能有效, 稳定性好
- 提供可靠性消息投递模式(confirm), 返回模式(return)等
- 与Spring完美整合, API丰富
- 集群模式丰富, 支持表达式配置, 高可用HA模式, 镜像队列模型
- 可以保证数据不丢失的前提下做到高可靠性, 可用性
RabbitMQ高性能的原因
- Erlang语言最初用于交换机领域的架构模式, 这样使得RabbitMQ在Broker之间进行数据交互的性能是非常优秀的
- Erlang的优点 : Erlang有着和原生Socket一样的延迟
AMQP协议
AMQP简介
- AMQP全称 : Advanced Message Queuing Protocol
- 中文 : 高级消息队列协议
- AMQP定义 : 是具有现代特征的二进制协议, 是一个提供统一消息服务的应用层标准高级消息队列协议, 是应用层协议的一个开放标准, 为面向消息的中间件设计
AMQP协议模型
AMQP核心概念
- Server : 又称Broker, 接受客户端连接, 实现AMQP实体服务
- Connection : 连接, 应用程序与Broker的网络连接
- Channel : 网络信道, 几乎所有的操作都在Channel中进行, Channel是进行消息读写的通道。客户端可以建立多个Channel, 每个Channel代表一个会话任务。
- Message : 消息, 服务器和应用程序之间传送的数据, 有Properties和Body组成。Properties可以对消息进行修饰, 比如消息的优先级, 延迟等高级特性; Body就是消息体内容。
- Virtual Host : 虚拟地址, 用于进行逻辑隔离, 最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue, 同一个Virtual Host里面不能有相同名称的Exchange或Queue
- Exchange : 交换机, 用于接收消息, 根据路由键转发消息到绑定的队列
- Binding : Exchange和Queue之间的虚拟连接, binding中可以包含routing key
- Routing Key : 一个路由规则, 虚拟机可用它来确定如何路由一个特定消息
- Queue : 也称Message Queue, 消息队列, 用于保存消息并将它们转发给消费者
RabbitMQ整体架构
架构图
- 生产者只需要将消息发送到Exchange即可
- 消费者只需要监听对应的消息队列即可
- Exchange绑定多个Queue时, 要通过Routing Key进行路由
RabbitMQ消息流转
RabbitMQ安装与使用
-
环境安装
- erlang下载
wget https://packages.erlang-solutions.com/erlang-solutions-2.0-1.noarch.rpm- erlang安装
解压
rpm -Uvh erlang-solutions-2.0-1.noarch.rpm安装
yum install -y erlang验证是否安装成功
erl -v -
RabbitMq下载、安装
- RabbitMq下载
GitHub下载RabbitMq - RabbitMq 安装 解压
rpm -Uvh rabbitmq-server-3.8.14-1.el7.noarch.rpm安装
yum install rabbitmq-server -y启动RabbimtMq
# 启动rabbiMq-server systemctl start rabbitmq-server # 查看是否启动成功 rabbiMq-Server systemctl status rabbitmq-server # 关闭rabbiMq-server systemctl stop rabbitmq-server # 开机重启 systemctl enable rabbitmq-server - RabbitMq下载
注意:在Centos8中有可能缺少 socat,可以使用命令
yum install -y socat进行安装
- WEB管理界面安装
rabbitmq-plugins enable rabbitmq_management
注意这需要开放端口号:15672,5672
firewall-cmd --permanent --zone=public --add-port=15672/tcp
firewall-cmd --permanent --zone=public --add-port=5672/tcp
重新加载配置使配置生效
firewall-cmd --reload
- 添加账户设置密码、授权
虚拟主机配置
- 创建虚拟主机 :
rabbitmqctl add_vhost vhostpath - 列出所有虚拟主机 :
rabbitmqctl list_vhosts - 列出虚拟主机上所有权限 :
rabbitmqctl list_permissions -p vhostpath - 删除虚拟主机 :
rabbitmqctl delete_vhostpath
用户配置
- 添加用户:
rabbitmqctl add_user [账号] [密码] - 添加角色:
rabbitmqctl set_user_tags [账号] [角色] - 变更密码:
rabbitmqctl change_password [用户名称] [新密码] - 删除用户:
rabbitmqctl delete_user [用户名称] - 列举所有用户:
rabbitmqctl list_users - 赋予、删除权限:
rabbitmqctl set_permissions -p [vhostpath] [用户名] ".*" ".*" ".*"
"." "." ".*" 表示所有资源的写权限和读权限。
- 清除用户权限:
rabbitmqctl clear_permissions -p [vhostpath] [用户名]
队列相关 :
- 查看所有队列信息 : rabbitmqctl list_queues
- 清除队列里的消息 : rabbitmqctl -p vhostpath purge_queue blue
编码
引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.9.0</version>
</dependency>
主要对象
- ConnectionFactory : 获取连接工厂
- Connection : 一个连接
- Channel : 数据通信信道, 可发送和接收消息
- Queue : 具体的消息存储队列
- Producer & Consumer生产者和消费者
快速入门
Producer
public class Producer {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String queueName = "queue_simple";
// 声明队列
/**
* queueName 队列名称
* durable 是否持久化 消息是否存盘 如果是非之久化队列消息也会存盘 但是消息随着服务器的重启会丢失,持久化了则不会
* exclusive:是否排外的,有两个作用,
* 一:当连接关闭时connection.close()该队列是否会自动删除;
* 二:该队列是否是私有的private,如果不是排外的,可以使用两个消费者都访问同一个队列,没有任何问题,
* 如果是排外的,会对当前队列加锁,其他通道channel是不能访问的,如果强制访问会报异常。
* autoDelete 是否自动删除 对最后一个消息被消费者消费后 ,队列是否删除
* argument 队列附带的属性
*/
channel.queueDeclare(queueName, false, false, false, null);
//发送消息
/**
* exchangeName 交换机 如果没有定义交换机 则使用默认的交换机
* routingKey 队列名称/routingkey
* props 消息的其他属性 - 路由标头等
* body 需要发送的消息内容
*/
for (int i = 0; i < 10000; i++) {
channel.basicPublish("", queueName, null, ("hello rabbitmq" + i).getBytes());
}
System.out.println("消息发送成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Consumer
/**
* @ClassName Consumer
* @Description TODO
* @Author Axel
* @Date 2021/4/17 18:55
* @Version 1.0
*/
@Slf4j
public class Consumer {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String queueName = "queue_simple";
channel.basicConsume(queueName, true,new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("收到的消息是:{} ------- {}", consumerTag, new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
log.info("消息接收失败!{}", consumerTag);
}
});
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Exchange 交换机
Direct Exchange:
所有发送到Direct Exchange的消息被转发到RoutingKey中指定的Queue。相当于把指定的RoutingKey和Queue建立路由关系。
注意 : Direct模式可以使用RabbitMQ自带的Exchange(default Exchange), 所以不需要将Exchange进行任何绑定(binding)操作, 消息传递时, RoutingKey必须完全匹配才会被队列接收, 否则该消息会被抛弃
Producer
package com.chou.rabbitmq.exchange.direct;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* exchange 类型为direct
*
* @author by Axel
* @since 2024/6/9 下午10:43
*/
@Slf4j
public class DirectExchangeProducerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_direct_Exchange";
String routing_key_Name = "direct_test_routing_key";
String queue_Name = "direct_test_queue";
//channel.queueDeclare(queue_Name, true, true, false, null);
// mandatory的作用:
// 当mandatory标志位设置为true时,如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
// 那么broker会调用basic.return方法将消息返还给生产者;当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;
// 通俗的讲,mandatory标志告诉broker代理服务器至少将消息route到一个队列中,否则就将消息return给发送者;
for (int i = 1; i <= 10; i++) {
channel.basicPublish(exchangeName, routing_key_Name, true, null, ("这是一个direct类型的Exchange交换机"+i).getBytes());
}
log.info("消息发送成功!");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Consumer
package com.chou.rabbitmq.exchange.direct;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Consumer
* @Description TODO
* @Author Axel
* @Date 2021/4/17 18:55
* @Version 1.0
*/
@Slf4j
public class DirectExchangeConsumerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_direct_Exchange";
String routing_key_Name = "direct_test_routing_key";
String queue_Name = "direct_test_queue";
channel.queueDeclare(queue_Name, true, true, false, null);
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT.getType(), true, false, null);
channel.queueBind(queue_Name, exchangeName, routing_key_Name);
channel.basicConsume(queue_Name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
try {
log.info("处理业务逻辑开始.....");
TimeUnit.SECONDS.sleep(1);
log.info("处理业务逻辑结束需要1秒.....");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("收到的消息是:{} ------- {}", consumerTag, new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
});
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
TopicExchange
- 所有发送到Topic Exchange的消息将被转发到所有关心RoutingKey中指定Topic的Queue上
- Exchange将RoutingKey和某个Topic进行模糊匹配, 此时队列需要绑定一个Topic
- 可以使用通配符进行模糊匹配
- "#" : 匹配一个或多个词
- "*" : 匹配一个词
Producer
package com.chou.rabbitmq.exchange.topic;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* exchange 类型为direct
*
* @author by Axel
* @since 2024/6/9 下午10:43
*/
@Slf4j
public class TopicExchangeProducerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_topic_Exchange";
String routing_key_Name1 = "topic.test.chou.cj";
String routing_key_Name2 = "topic.test.zhou";
String routing_key_Name3 = "topic.test.chou";
//mandatory的作用:
//当mandatory标志位设置为true时,如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
//那么broker会调用basic.return方法将消息返还给生产者;当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;
//通俗的讲,mandatory标志告诉broker代理服务器至少将消息route到一个队列中,否则就将消息return给发送者;
channel.basicPublish(exchangeName, routing_key_Name1, true,
null, ("这是一个Topic类型的Exchange交换机routing_key:routing_key_Name1").getBytes());
channel.basicPublish(exchangeName, routing_key_Name2, true,
null, ("这是一个Topic类型的Exchange交换机routing_key:routing_key_Name2").getBytes());
channel.basicPublish(exchangeName, routing_key_Name3, true,
null, ("这是一个Topic类型的Exchange交换机routing_key:routing_key_Name3").getBytes());
log.info("消息发送成功!");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Consumer
package com.chou.rabbitmq.exchange.topic;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @ClassName Consumer
* @Description TODO
* @Author Axel
* @Date 2021/4/17 18:55
* @Version 1.0
*/
@Slf4j
public class TopicExchangeConsumerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_topic_Exchange";
String routing_key_Name = "topic.test.#";
//String routing_key_Name = "topic.test.#";
String queue_Name = "topic_test_queue";
channel.queueDeclare(queue_Name, true, true, false, null);
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC.getType(), true, false, null);
channel.queueBind(queue_Name, exchangeName, routing_key_Name);
channel.basicConsume(queue_Name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("收到的消息是:{} ------- {}", consumerTag, new String(message.getBody(), StandardCharsets.UTF_8));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
});
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Fanout Exchange
- 不处理路由键, 只需要简单的将队列绑定到交换机上
- 发送到交换机的消息都会被转发到与该交换机绑定的所有队列上
- Fanout交换机转发消息是最快的
Producer
package com.chou.rabbitmq.exchange.fanout;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* exchange 类型为direct
*
* @author by Axel
* @since 2024/6/9 下午10:43
*/
@Slf4j
public class FanoutExchangeProducerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_fanout_Exchange";
String routing_key_Name = "没有什么用";
//mandatory的作用:
//当mandatory标志位设置为true时,如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
//那么broker会调用basic.return方法将消息返还给生产者;当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;
//通俗的讲,mandatory标志告诉broker代理服务器至少将消息route到一个队列中,否则就将消息return给发送者;
for (int i = 1; i <=5 ; i++) {
channel.basicPublish(exchangeName, routing_key_Name, true,
null, ("这是一个Fanout类型的Exchange交换机routing_key:routing_key_Name" + i).getBytes());
}
log.info("消息发送成功!");
} catch (Exception e) {
log.error(">>>>>>>>fanoutExchangeProducerTest occur error",e);
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Comsumer
package com.chou.rabbitmq.exchange.fanout;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author Axel
* @since 2021/4/17 18:55
*/
@Slf4j
public class FanoutExchangeConsumerTest {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String exchangeName = "customer_fanout_Exchange";
String routing_key_Name = "";
String queue_Name = "fanout_test_queue";
channel.queueDeclare(queue_Name, true, true, false, null);
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT.getType(), true, false, null);
channel.queueBind(queue_Name, exchangeName, routing_key_Name);
channel.basicConsume(queue_Name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("收到的消息是:{} ------- {}", consumerTag, new String(message.getBody(), StandardCharsets.UTF_8));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
});
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Headers Exchange
- Headers Exchange不使用RoutingKey去绑定, 而是通过消息headers的键值对匹配
- 这个Exchange很少会使用, 这里就暂时不展开
代码中对象或者属性介绍
Virtual Host-虚拟主机
- 虚拟地址, 用于进行逻辑隔离, 最上层的消息路由
- 一个Virtual Host里面可以有若干个Exchange和Queue
- 同一个Virtual Host里面不能有相同名称的Exchange或Queue 例如代码中
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setVirtualHost("/");给当前的程序指定分区。
Binding-绑定
- Exchange和Exchange, Queue之间的连接关系
- 绑定中可以包含RoutingKey或者参数
Queue-消息队列
- 消息队列, 实际存储消息数据
- Durability : 是否持久化
Durable : 是
Transient : 否 - Auto delete : 如选yes,代表当最后一个监听被移除之后, 该Queue会自动被删除
Message消息
- 服务和应用程序之间传送的数据
- 本质上就是一段数据, 由Properties和Payload(Body)组成
- 常用属性 : delivery mode, headers(自定义属性)
Message消息的其他属性
- content_type, content_encoding, priority
- correlation_id : 可以认为是消息的唯一id
- replay_to : 重回队列设定
- expiration : 消息过期时间
- message_id : 消息id
- timestamp, type, user_id, app_id, cluster_id
编码实例
Producer
package com.chou.rabbitmq.message;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* 生产这
*
* @author by Axel
* @since 2024/7/29 下午9:21
*/
@Slf4j
public class Producer {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String msg = "这是一个message消息测试类";
//mandatory的作用:
//当mandatory标志位设置为true时,如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
//那么broker会调用basic.return方法将消息返还给生产者;当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;
//通俗的讲,mandatory标志告诉broker代理服务器至少将消息route到一个队列中,否则就将消息return给发送者;
Map<String,Object> headers = new HashMap<>();
headers.put("name", "Choucj");
AMQP.BasicProperties basicProperties = new AMQP.BasicProperties()
.builder()
.headers(headers)
.contentEncoding(StandardCharsets.UTF_8.name())
.expiration("5000")
.build();
for (int i = 1; i <= 5; i++) {
// 使用默认的exchange,routingKey与队列名称对齐
channel.basicPublish("","msgTest",true,basicProperties,msg.getBytes());
}
log.info("消息发送成功!");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
Consumer
package com.chou.rabbitmq.message;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* 消费者
*
* @author by Axel
* @since 2024/7/29 下午9:22
*/
@Slf4j
public class Consumer {
public static void main(String[] args) {
Channel channel = null;
Connection connection = null;
try {
// 所有的中间件技术都是基于tcp/ip协议的基础上构建新型的协议规范,只不过rabbitmq 遵循的是amqp协议
// 设置连接属性创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.115");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
// 获取连接对象
connection = connectionFactory.newConnection();
// 创建通信通道
channel = connection.createChannel();
String queue_Name = "msgTest";
channel.queueDeclare(queue_Name, true, true, false, null);
channel.basicConsume(queue_Name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("收到的消息是:{} ------- {}", consumerTag, new String(message.getBody(), StandardCharsets.UTF_8));
Object name = message.getProperties().getHeaders().get("name");
log.info("收到的消息属性值是:{} ------- {}", consumerTag, name);
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
});
System.in.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel && channel.isOpen()) {
try {
channel.close();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
if (null != connection && connection.isOpen()) {
try {
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}