介绍:
RabbitMQ提供了6中消息模型 但第6种其实是RPC(远程过程调用)并不是MQ (message queue 消息队列) 所以暂时咱还不研究 如果想去了解RPC的话可以去学习一下dubbo 它就是一个轻量级的开源 RPC框架,今天咱们学习第一种 RrabbitMQ消息模型——基本消息模型
如图所示 基本消息模型就是生产者------->消息队列------>消费者,消息生产者对应一个消息消费者:
搭建示例工程:
项目目录结构:
1、创建springboot项目导入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、创建工具类ConnectionUtil 因为消息生产者和消息消费都需要获取连接对象,所以在这里我们将获取连接的代码进行封装
package com.rabbitmq.utils;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author: shenwang
* Date: 2021/7/3
*/
public class ConnectionUtil {
public static Connection getConnection(){
Connection connection=null;
//创建连接工厂对象
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置RabbitMQ服务主机地址,默认localhost
connectionFactory.setHost("localhost");
//设置rabbitmq服务端口,默认5672
connectionFactory.setPort(5672);
//设置虚拟机名字,默认/
connectionFactory.setVirtualHost("/");
//设置用户连接名 默认guest
connectionFactory.setUsername("ahua");
//设置连接密码 默认guest
connectionFactory.setPassword("123");
try {
//创建连接
connection= connectionFactory.newConnection();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return connection;
}
}
3、消息生产者:
package com.rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.utils.ConnectionUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消息生产者
* @author: shenwang
* Date: 2021/7/2
*/
public class Producer {
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = ConnectionUtil.getConnection();
//创建频道
Channel channel = connection.createChannel();
/**
* 声明式队列
* 参数1:列队名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其他参数
*/
channel.queueDeclare("simple_queue",true,false,false,null);
//创建消息
String message="hello world! my name is ahua";
/**
* 发送消息
* 参数1:交换机名称,如果没有指定则使用默认 default Exchange
* 参数2:路由key,简单模式可以传递队列名称
* 参数3:消息其他属性
* 参数4:消息内容
*/
channel.basicPublish("","simple_queue",null,message.getBytes());
//关闭资源
channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
启动咱们的消息生产者类可以在咱们的RabbitMQ Management中看到消息:
4、消息消费者
package com.rabbitmq.simple;
import com.rabbitmq.client.*;
import com.rabbitmq.utils.ConnectionUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消息消费者
* @author: shenwang
* Date: 2021/7/3
*/
public class Consumer {
public static void main(String[] args) {
try {
//创建连接
Connection connection = ConnectionUtil.getConnection();
//创建频道
Channel channel = connection.createChannel();
/**
* 声明式队列
* 参数1:列队名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其他参数
*/
channel.queueDeclare("simple_queue",true,false,false,null);
//创建消费者 并设置消息处理
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
/**
*
* @param consumerTag 消息者标签,在channel.basicConsumer时候可以指定
* @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息后是否需要重新发送)
* @param properties 属性消息
* @param body 消息
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由的key
String routingKey = envelope.getRoutingKey();
//获取交换机信息
String exchange = envelope.getExchange();
//获取消息id
long deliveryTag = envelope.getDeliveryTag();
//获取消息信息
String message = new String(body,"UTF-8");
//测试
System.out.println("routingKey:"+routingKey);
System.out.println("exchange:"+exchange);
System.out.println("deliveryTag:"+deliveryTag);
System.out.println("message:"+message);
}
};
/**
* 消息监听
* 参数1:队列名称
* 参数2:是否自动确认,设置为true表示收到自动像mq回复收到了,mq接受到回复会删除消息,设置为false则需要手动确认
* 参数3:消息收到后回调
*/
channel.basicConsume("simple_queue",true,defaultConsumer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
最后咱们那个消息手动确认机制 啥时候手动 啥时候自动嘞:
/*
* 消息监听
* 参数1:队列名称
* 参数2:是否自动确认,设置为true表示收到自动像mq回复收到了,mq接受到回复会删除消息,设置为false则需要手动确认
* 参数3:消息收到后回调
*/
channel.basicConsume("simple_queue",true,defaultConsumer);
对于不是很重要的消息,丢失了对咱的系统没啥影响的话 咱们可以使用自动Ack会比较方便。
对于很重要的消息,不允许该消息丢失的情况下那么我们就应该使用手动Ack来进行消息确认,防止消息丢失。