今天要聊的是RabbitMQ的最基本的消息模型,就是一个消息生产者生产消息对应一个消费者消息消息。如下图
一、搭建项目
首先搭建项目
<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.16.0</version>
</dependency>
二、生产者代码实现
之前有期讲过MQ工作的原理,MQ消息队列(四)RabbitMQ原理及组件_丁胜利v的博客-优快云博客
我们可以看到,要把消息从生产者到消费者需要几个角色的参与,分别是信道Channel,交换机Exchange和队列Queue。
1.创建连接2.创建信道
3.创建交换机
4.创建队列
5.将消息发送至指定队列
//=======================先创建与RabbitMQ的连接(建议抽成工具类)=======================
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址和端口
factory.setHost("127.0.0.1");
factory.setPort(5672);
//设置账号信息,用户名、密码、vhost
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
//通过工厂拿到连接
connection = factory.newConnection();
import cn.victory.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import static com.rabbitmq.client.BuiltinExchangeType.DIRECT;
public class ProducerBase {
//交换机名称
private static final String EXCHANGE = "VictoryExchangeBase";
//队列名称
private static final String QUEUE = "VictoryQueueBase";
//路由键
private static final String ROUTINGKEY = "VictoryRoutingKeyBase";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
try {
//=============先创建与RabbitMQ的连接=============
connection = ConnectionUtil.getConnection();
//=============创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务=============
channel = connection.createChannel();
//=============声明交换机=============
channel.exchangeDeclare(EXCHANGE,DIRECT,false,false,false,null);
//=============声明队列=============
channel.queueDeclare(QUEUE,false,false,false,null);
//=============将队列绑定到交换机=============
channel.queueBind(QUEUE,EXCHANGE,ROUTINGKEY);
/**=============发送消息=============
*
* 如果没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定默认的交换机,routingKey等于队列名称
*
* param exchange:交换机名称
* param routingKey:路由键
* param mandatory:当mandatory标志位设置为true时,如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,那么broker会调用basic.return方法将消息返还给生产者;当mandatory设置为false时,出现上述情况broker会直接将消息丢弃
* param immediate:当immediate标志位设置为true时,如果exchange在将消息路由到queue(s)时发现对应的queue上么有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的所有queue都没有消费者时,该消息会通过basic.return方法返还给生产者。
* param props:消息属性字段,比如消息头部信息等等
* param body:消息主体
*
**/
String message = "HelloVic" + System.currentTimeMillis();
channel.basicPublish(EXCHANGE,ROUTINGKEY,true,false, null, message.getBytes());
System.out.println("Send Message is:'" + message + "'");
//=============关闭信道和连接=============
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
登录Rabbit管理页面http://localhost:15672,默认账号密码都是guest
可以看到交换机创建成功
队列创建成功且队列中有一条消息
点进去可以看到这条消息就是刚刚我们发送出来的那条
三、消费者代码实现
import cn.victory.util.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
public class ConsumerBase {
private static final String QUEUE = "VictoryQueueBase";
public static void main(String[] args) throws Exception {
//=============创建连接=============
Connection connection = ConnectionUtil.getConnection();
//=============创建通道=============
Channel channel = connection.createChannel();
//=============声明队列=============
channel.queueDeclare(QUEUE, false, false, false, null);
// 创建消费者,并设置收到消息的回调函数
Consumer consumer = 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("consumerTag: " + consumerTag);
System.out.println("envelope.getExchange():" + envelope.getExchange());
System.out.println("envelope.getRoutingKey():" + envelope.getRoutingKey());
System.out.println("envelope.getDeliveryTag():" + envelope.getDeliveryTag());
System.out.println("envelope.isRedeliver():" + envelope.isRedeliver());
System.out.println("收到消息: " + message);
}
};
//=============监听队列=============
/**
* 监听队列
* @param queue 队列名
* @param autoAck 消息确认机制,为true时
* 消息一旦被当前消费者接收到,RabbitMQ就会认为该消息被正确消费,
* 会将其从队列中移除,为false时,消息一旦被当前消费者接收到,
* RabbitMQ不会认为该消息被正确消费,会将其保留在队列中,
* 等待下次被消费
* @param consumerTag 消费者标签
* @param noLocal 为True时不能将同一个Connection中生产者发送的消息传递给这个Connection中的消费者
* @param exclusive 是否为独占队列
* @param arguments 队列参数
* @param deliverCallback 消息传递成功时的回调
* @param cancelCallback 要通知取消使用者的回调接口
* @param shutdownSignalCallback 信息通道或者连接关闭时的回调
* @return 与新消费者关联的消费者标签
* @since 5.0
*/
channel.basicConsume(QUEUE, true, consumer);
}
}
启动消费者,可以看到之前生产者测试时放入队列中的消息被消费掉了,但是程序没有停止,一直在监听队列中是否有新的消息。一旦有新的消息进入队列,就会立即打印.
基本消息模型代码基本上就这些,具体需要哪些参数在方法中添加对应参数即可,具体的手动签收计划放在后面讲完消息模型之后将如何保证消息不丢失和不被重复消费时再聊。最后求波关注求波赞,给您磕一个~