最近在学习消息队列RabbitMQ相关的知识,打算把自己的理解写下来,包括踩过的坑,记录一下,也分享给大家,欢迎评论区批评指正。话不多说,进入正题……
什么是消息队列
消息队列(Message Queue),本质也是一个队列,所以消息也会符合先进先出的规则。消息队列是一种跨进程的通信机制,被用于上下游传递消息。
RabbitMQ安装和环境配置
安装
我使用的是Docker环境安装的RabbitMQ镜像
# 查询所有的RabbitMQ镜像
docker search rabbitmq
# 安装RabbitMQ
docker pull rabbitmq
# 运行RabbitMQ镜像 -d表示在后台运行 -p端口映射 --name 自定义容器名称 容器ID
docker run -d -p 5672:5672 -p 15672:15672 --name myrabbit
# 查看运行的镜像
docker ps -a
# 启动RabbitMQ
docker start 进程ID
# 安装RabbitMQ插件可以让我们进入到RabbitMQ的管理页面
rabbitmq-plugins enable rabbitmq_shovel rabbitmq_shovel_management
以上就是docker安装的步骤了,在浏览器中输入RabbitMQ主机的IP:15672,如果出现下面的页面,说明咱的RabbitMQ就安装配置成功了。用户名和密码都是guest

点击login之后会进入到管理的主页面

在这里可以管理连接(Connection)、通道(Channel)、交换机(Exchange)、队列(Queue)等RabbitMQ的主要配置。
Maven项目开发设置
-
引入依赖
<!-- 引入RabbitMQ相关依赖 --> <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.9.0</version> </dependency> -
RabbitMQ连接工具的封装
public class RabbitMQUtil { // 使用静态资源创建连接MQ的连接工厂对象 public static ConnectionFactory connectionFactory; // 类加载之前只执行一次 static { connectionFactory = new ConnectionFactory(); // 设置连接RabbitMQ的主机 connectionFactory.setHost("127.0.0.1"); // 设置端口号 connectionFactory.setPort(5672); // 设置虚拟主机 connectionFactory.setVirtualHost("/ems"); // 设置用户名 connectionFactory.setUsername("ems"); // 设置密码 connectionFactory.setPassword("123"); } // 提供创建连接对象的方法 public static Connection getConnection(){ try { // 获取连接对象 return connectionFactory.newConnection(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } return null; } // 关闭通道和连接的方法 public static void closeConnectionAndChannel(Channel channel, Connection connection) { try { if (channel != null) { channel.close(); } if (connection != null) { connection.close(); } } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }为了我们连接方便,不用每次在定义publisher和consumer的时候都要写过长的连接代码,这里我们封装了一个工具类。要设置RabbitMQ安装的主机的IP地址(Host)、用户名(username)、密码(password)、虚拟主机(virtualHost)以及虚拟主机的用户名和密码。
为了避免资源的浪费,在使用完连接和通道之后我们可以关闭通道,所以还封装了关闭连接和通道的方法。
连接工厂对象是一个高内存占用的资源,如果每次连接都要创建一个对象,十分占用我们的内存,所以我们使用静态资源创建连接MQ的连接工厂对象,静态资源只在类加载的时候初始化一次,这样大大节省了我们的资源占用。
RabbitMQ的模型
HelloWorld–直连模型
直连模型:只有一个生产者和一个消费者,生产者负责生产消息,放入到消息队列中;消费者负责从消息队列中取消息,消费消息。

图中P代表生产者,中间红色的部分代表消息队列,C代表消费者。消息队列就是存放消息的缓冲区。
直连模型应该是最容易理解的模型了。与RabbitMQ对比,传统的做法是生产者发布消息,不经过消息队列的缓存,消费者直接消费。这样的做法不适合高频率的消息发送,如果生产者发布消息的频率过快,消费者就会承担消费消息的巨大压力,很容易崩溃。
有了RabbitMQ,生产者发布消息后可以经过消息队列的缓存,消费者再从消息队列中取消息进行消费。这样就避免了消费者承担频率过高的处理工作。
代码实现
消息生产者Publisher
public class Publisher {
// 声明消息队列的名称
public static final String QUEUE_NAME = "hello";
public static void main(String[] args) throws IOException {
// 获取连接
Connection connection = RabbitMQUtil.getConnection();
// 创建通道
Channel channel = connection.createChannel();
// 声明绑定队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
// 消息内容
String message = "Hello World!";
// 发布消息
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
// 关闭通道和连接
RabbitMQUtil.closeConnectionAndChannel(channel, connection);
}
}
==queueDeclare(QUEUE_NAME,false,false,false,null)==方法参数说明:
- QUEUE_NAME:队列名称,如果队列不存在自动创建
- false:用来定义队列特性是否要持久化,true–持久化 false–不持久化
- fasle:exclusive参数表示是否独占队列,true–独占 false–不独占
- fasle:消息完成后是否自动删除队列,true–自动删除 false–不自动删除
- null:附加参数,以map形式呈现,如果没有则为null。
==basicPublish("",QUEUE_NAME,null,message.getBytes())==方法参数说明:
- Exchange:交换机名称,(因为我们的直连模型没有用到交换机,所以这里的参数我们选择为空字符串)
- QUEUE_NAME:队列名称,表示要把消息发布到哪个消息队列
- null:传递消息额外设置,如果没有可以选择为空,(MessageProperties.PERSISTENT_TEXT_PLAIN,表示消息内容的持久化)
- message.getBytes():字节形式的消息内容
消息消费者Consumer
public class Consumer {
public static final String QUEUE_NAME = "hello";
public static void main(String[] args) throws IOException {
// 获取连接并创建通道
Connection connection = RabbitMQUtil.getConnection();
Channel channel = connection.createChannel();
// 绑定对应的消息队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
// 消费消息
channel.basicConsume(QUEUE_NAME,true, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
});
}
}
==basicConsume(QUEUE_NAME,true, new DefaultConsumer(channel) {})==方法参数说明:
-
QUEUE_NAME:消息队列的名字,表示要消费哪个队列的消息
-
true:是否开启消息的自动确认机制,true–开启 false–不开启
-
new DefaultConsumer(channel) {}:消费消息时的回调接口
-
重写消息处理函数
@Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { // 消息体转换为字符串 String message = new String(body, "UTF-8"); System.out.println(" [x] Received '" + message + "'"); }
-
创建完消息生产者和消息的消费者,我们就可以进行测试了。首先运行Publisher.java,向消息队列中发送“Hello World!”消息。

发送消息过后,在RabbitMQ的管理页面,可以看到消息队列中创建了名为“hello”的队列,消息队列中的消息数量也从0变成了1。说明我们成功实现了向消息队列中发送消息。

接下来,就是消费者方面。运行Consumer.java,控制台输出如下。说明消息消费者成功输出接收的消息,并在控制台输出成功。

打开RabbitMQ的管理页面,可以发现,名为“hello”的消息队列中的消息数量从1变成了0,说明消息生产者向消息队列中生产的消息被消息消费者进行消费了。

注意:生产者和消费者产生中绑定消息队列方法的参数值必须要相同,不然RabbitMQ一定会报错

关于RabbitMQ的简单入门就先写这么多了,还有几种经典的模型。上面的直连模型一般是不怎么使用的,不过可以在我们学习RabbitMQ的初级阶段,帮助我们更好的理解消息队列的原理。
如果有错误,请大家评论区批评指正,谢谢大家~
本文介绍了RabbitMQ的基本概念,通过Docker安装配置RabbitMQ,并展示了直连模型的代码实现,包括消息生产者和消费者的创建。文章强调了消息队列在缓解高频率消息处理压力中的作用。
372





