文章目录
参考蚂蚁课堂
1.RabbitMQ基本介绍
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件),RabbitMQ服务器是用Erlang语言编写的。然后我们安装rabbitMQ就行了,安装完之后访问localhost://15672即可进入到rabbitMQ管理平台,然后输入账号密码登录,账号密码为guest,guest。
这里面有一个Virutual Hosts的概念,这个相当于RabbitMQ的虚拟消息服务器VirtualHost,每个VirtualHost相当于一个相对独立的RabbitMQ服务器,每个VirtualHost之间是相互隔离的,exchange,queue,message不能互通。
然后我们看一下RabbitMQ常见的端口号
15672 — RabbitMQ管理平台的端口号
25672 — 集群通信端口号
Amqp 5672 — RabbitMQ内部通信的一个端口号
2.RabbitMQ简单使用案例
RabbitMQ使用的一般步骤首先要在管理平台端创建一个队列,然后编写生产者代码,然后编写消费者代码。
2.1在RabbitMQ平台上创建一个队列
首先先创建一个VirtualHost,然后设置Permission设置成自己的账号guest
然后我们就可以在这个VirtualHost里面创建Queue。
添加队列的时候要指明这个队列属于哪个VirtualHost,然后设置一个队列名称,然后Durability设置是否可以持久化。然后添加就完事了。
2.2编写生产者代码
这个生产者的任务就是向消息队列中投放消息,首先他必须要和RabbitMQ建立一个连接。
public class RabbitMQConnection {
public static Connection getConnection() throws IOException, TimeoutException {
//1.创建connectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.配置Host
connectionFactory.setHost("127.0.0.1");
//3.设置Port
connectionFactory.setPort(5672);
//4.设置账户和密码
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//5.设置VirtualHost
connectionFactory.setVirtualHost("/wjzVirtualHost");
return connectionFactory.newConnection();
}
}
配置好我们的IP地址端口号和VirtualHost。然后我们编写生产者代码
public class Producer {
private static final String QUEUE_NAME = "wjz-queue";
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建一个新连接
Connection connection = RabbitMQConnection.getConnection();
//2.设置channel
Channel channel = connection.createChannel();
//3.发送消息
String msg = "wjz,nb!!!";
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
System.out.println("消息投递成功");
channel.close();
connection.close();
}
}
生产者这边要建立和RabbitMQ服务器之间的连接,然后向消息队列中发送消息,然后关闭连接。然后basicPublish第一个参数是交换机我们这个比较简单就没有,然后第二个是消息队列名称你的队列的名叫啥你就写啥,第三个参数是props一些配置信息比如说过期时间,优先级,投递模式之类的,第四个参数是消息。
然后我们运行一下看看这条消息有没有被投递到MQ服务器。
如图所示,队列里的Ready为1,然后我们下一步就是把消息队列里的消息从队列中取出来。
2.3编写消费者代码
public class Consumer {
private static final String QUEUE_NAME = "wjz-queue";
public static void main(String[] args) throws IOException, TimeoutException, IOException, TimeoutException {
// 1.创建连接
Connection connection = RabbitMQConnection.getConnection();
// 2.设置通道
Channel channel = connection.createChannel();
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("消费者获取消息:" + msg);
// 消费者完成 消费该消息
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
// 3.监听队列
channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
}
}
消费者我们也是首先创建一个连接,然后设置通道,在这个通道里面拿到消息之后消费掉。最后这个监听队列这个,第二个参数如果设置为true就是自动签收,我获取成功了就会立即从消息队列中移除。但是如果说我这个消息正在处理然后处理失败了,这个时候我要做一个补偿,但是这个时候MQ里已经没有了这条消息。这是不对的所以我们一般都是手动签收把这个参数设置为false。手动签收就是我消费者收到消息之后如果成功消费了会发给MQ一个通知这个时候MQ才会清除。
好了解释完了运行一下看看结果。
3.RabbitMQ如何保证消息不丢失
MQ服务器端在默认的情况下都会对队列中的消息实现持久化。所以就算MQ宕机里面的消息也不会丢失。
如图所示为了保证消息不丢失RabbitMQ有一个消息确认机制,生产者向队列投递一条消息,同时MQ回向生产者返回一个消息确认。这样就确保了生产者投递信息到MQ一定是成功的。这个MQ发回给生产者的Ack可以使用同步或者异步机制,同步的话就是如果MQ服务器不返回确认生产者就会阻塞,异步的话就是有一个观察者监听是否投递成功,如果投递成功MQ返回一个确认给生产者。
消费者必须要将消息消费成功之后就会发一个通知给MQ服务器让MQ把消息从队列当中删除。
4.RabbitMQ工作队列
默认的传统队列是为均摊消费,存在不公平性;如果每个消费者速度不一样的情况下,均摊消费是不公平的。我们希望达到一个能者多劳的效果。这就需要我们采用工作队列。工作队列的实现就是两个消费者能者多劳,能力强的多分配,能力弱的少分配,我们可以通过channel.basicQos(int);这个函数来设置这个消费者一次要从队列中拉取多少条消息,同时给MQ服务器端发送一个Ack确认消息已经被处理了这样MQ会从队列中删除这条消息。
下面我们可以通过代码来演示一下这个效果
producer
public class Producer {
private static final String QUEUE_NAME = "wjz-queue";
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建一个新连接
Connection connection = RabbitMQConnection.getConnection();
//2.设置channel
Channel channel = connection.createChannel();
//3.发送消息
for (int i = 0; i < 10; i++) {
String msg = "wjz nb:i" + i;
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
}
System.out.println("消息投递成功");
channel.close();
connection.close();
}
}
首先这个生产者会和MQ服务器建立一个连接,然后向MQ中投放10条消息。
consumer1
public class Consumer1 {
private static final String QUEUE_NAME = "wjz-queue";
public static void main(String[] args) throws IOException, TimeoutException, IOException, TimeoutException {
// 1.创建连接
Connection connection = RabbitMQConnection.getConnection();
// 2.设置通道
Channel channel = connection.createChannel();
//指定我们消费者每次批量获取消息
channel.basicQos(2);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("消费者获取消息:" + msg);