第一种模型(HelloWorld)

上图来自官方文档

P代表生产者用来生产消息,发送给消费者C,中间的共色部分代表消息队列,用来缓存消息。

首先导入依赖

<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.2</version>
</dependency>

工具类 RabbitmqUtil.java

public class RabbitmqUtil {

    private static ConnectionFactory connectionFactory = new ConnectionFactory();

    /**
* 配置连接端口,ip,用户名和密码
*/
static {
//绑定RabbitMQ主机地址
connectionFactory.setHost("192.168.1.6");
//绑定端口
connectionFactory.setPort(5672);
//输入用户名密码
connectionFactory.setUsername("rabbit");
connectionFactory.setPassword("rabbit");
} /**
* 获取连接对象
* @return
*/
public static Connection getConnection() {
try {
return connectionFactory.newConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 关闭资源
* @param channel
* @param connection
*/
public static void closeConnAndChannel(Channel channel,Connection connection){
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}

生产者代码
Provider.java

public class Provider {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通道
Channel channel = connection.createChannel(); //queueDeclare第一个参数是队列名称,第二个是是否持久化,如果是true,队列持久化,但是队列内容的持久化需要在basicProperties设置
//第三个是是否独占队列一般是false不独占,第四个是消费完成后是否自动删除 true代表删除,false代表不删除
//第五个参数是额外附加参数 channel.queueDeclare("hello",true,false,true,null);
//basicPublish 第一个参数代表交换机名称,第二是队列名称,第三个是额外的队列配置 第四个参数就是发送的消息
channel.basicPublish("","hello", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello,world".getBytes()); //关闭管道和连接
RabbitmqUtil.closeConnAndChannel(channel,connection); } }

Consumer.java

public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 通过工具类获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通道
Channel channel = connection.createChannel();
// '参数1':用来声明通道对应的队列 hello
// '参数2':用来指定是否持久化队列 true
// '参数3':用来指定是否独占队列 false 一般都是不独站队列 让多个连接可以共同向一个队列生产消费消息
// '参数4':用来指定是否自动删除队列 false
// '参数5':对队列的额外配置 是一个Map类型
channel.queueDeclare("hello",true,false,true,null);
//参数一代表队列名,参数二是否开启自动确认机制,参数三,消费时的回调接口
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接收的消息是:"+new String(body));
}
});
} }

第二种模型(Work queue)

C1和C2都是消费者,P代表生产者,中间红色的部分是消息队列。

Work queue被称为任务队列。当消息处理比较耗时时,生产的速度大于消费的速度,长此以往,消息会在消息队列中越来愈多,无法及时处理。此时可以使用work模型,让多了消费者绑定到一个队列中,共同消费队列中的消息。

消息提供者

public class Provider {

    public static void main(String[] args) throws IOException {
Connection connection = RabbitmqUtil.getConnection();
//建立通道
Channel channel = connection.createChannel();
//建立队列
channel.queueDeclare("work",false,false,false,null);
//生产消息
for (int i = 0; i < 10; i++) {
channel.basicPublish("","work",null,(i+":work queue").getBytes());
}
//关闭资源
RabbitmqUtil.closeConnAndChannel(channel,connection); } }

消费者1

public class Consumer1 {
public static void main(String[] args) throws IOException { // 通过工具类获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通道
Channel channel = connection.createChannel();
//每次只确认一条消息
channel.basicQos(1);
// '参数1':用来声明通道对应的队列 hello
// '参数2':用来指定是否持久化队列 true
// '参数3':用来指定是否独占队列 false 一般都是不独站队列 让多个连接可以共同向一个队列生产消费消息
// '参数4':用来指定是否自动删除队列 false
// '参数5':对队列的额外配置 是一个Map类型
channel.queueDeclare("work",false,false,false,null);
//参数一代表队列名,参数二是否开启自动确认机制,参数三,消费时的回调接口
channel.basicConsume("work",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者 1 接收的消息是:"+new String(body));
//进行手动确认
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}

消费者2

public class Consumer2 {
public static void main(String[] args) throws IOException { // 通过工具类获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通道
Channel channel = connection.createChannel();
//一次只接受1条消息进行 确认
channel.basicQos(1);
// '参数1':用来声明通道对应的队列 hello
// '参数2':用来指定是否持久化队列 true
// '参数3':用来指定是否独占队列 false 一般都是不独站队列 让多个连接可以共同向一个队列生产消费消息
// '参数4':用来指定是否自动删除队列 false
// '参数5':对队列的额外配置 是一个Map类型
channel.queueDeclare("work",false,false,false,null);
//参数一代表队列名,
// 参数二是否开启自动确认机,
// 在开启自动确认消息机制时,RabbitMQ会认为只要消费者从队列中拿走消息就认为已经消费完成,就会将队列中的消息标记为已消费实际消费过程中有可能出现
//开启自动确认机制有时会造成消息丢失,如果一个消费者在执行过程中宕机了那他未完成的消息也会丢失,我们想让宕机后未消费的消息转移到正常运行的消费者上进行消费,
// 所以需要关闭自动确认机制(设置成false),进行手动确认
// 参数三,消费时的回调接口
channel.basicConsume("work",false,new DefaultConsumer(channel){
@lombok.SneakyThrows
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 消费者2消费的速度小于消费者1
Thread.sleep(2000);
System.out.println("消费者 2 接收的消息是:"+new String(body));
//进行手动确认消息 false代表不开启多次确认
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}

上面的代码是进行手动确认消息,默认是自动确认消息,如果是默认的自动消息确认机制,那么消息提供者会将消息平均发送给消费者1和消费者2。也就是说消费者收到的消息数量是相同的,有序的,这种消费发送方式也被叫做循环。

但是我们通常会根据消费者处理的效率不同,让消费快的消费者处理多点消息;消费效率低的消费者处理少量的消息。

第三种模型(Fanout)

扇出(fanout)又称广播
广播模式下,消息发送流程

  • 可以有多个消费者
  • 每个消费者都有自己的队列
  • 每个队列都要绑定到Exchange(交换机)
  • 生产者发送消息,只能发送给交换机,交换机决定要发送到哪个队列,生产者无法决定
  • 交换机把消息发送给绑定过的所有队列
  • 队列的消费者都能够拿到消息,实现一条消息被多个消费者消费
    代码实现

消息生产者

public class Provider {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitmqUtil.getConnection();
//获取管道
Channel channel = connection.createChannel();
//将管道绑定交换机
channel.exchangeDeclare("logs","fanout");
//发送消息内容
channel.basicPublish("logs","",null,"fanout 广播模式".getBytes());
//关闭连接
RabbitmqUtil.closeConnAndChannel(channel,connection);
}
}

消费者

public class Consumer1 {
public static void main(String[] args) throws IOException { Connection connection = RabbitmqUtil.getConnection();
Channel channel = connection.createChannel();
//绑定交换机
channel.exchangeDeclare("logs","fanout"); //临时队列
String queue = channel.queueDeclare().getQueue(); //绑定交换机和队列
channel.queueBind(queue,"logs",""); //消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
System.out.println("消费者1: "+new String(body));
}
}); }
}

其中一个生产者多个消费者进行消费,广播的效果就是可以将同一条消息发送给所有消费者绑定的队列

第四种模式(Routing)

Routing订阅模式-Direct(直连)
在Fanout模式中,一条消息,会被所有订阅的队列都消费但是在某些场景下,我们希望不同的消息被不同的队列消费。这时候就要用到Direct类型的Exchange。
在Direct下:
1、队列与交换机的绑定不能是任意绑定,而是要指定一个RoutingKey(路由Key)
2、消息的发送方在向交换机发送消息时,需要指定RoutingKey。
3、Exchange不在吧消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的RoutingKey与消息的Routing Key完全一致才会接收到消息。

消息生产者

public class Provider {
public static void main(String[] args) throws IOException {
// 获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通信管道
Channel channel = connection.createChannel();
// 交换器名称
String exechange = "logs_direct";
channel.exchangeDeclare(exechange,"direct");
// 指定路由key
String router_key = "error";
// 向交换器发送消息
channel.basicPublish(exechange,router_key,
null,("这是基于direct模型发布的 route_key="+router_key+" 发送的消息").getBytes());
RabbitmqUtil.closeConnAndChannel(channel,connection);
}
}

消费者1

public class Consumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitmqUtil.getConnection();
Channel channel = connection.createChannel(); String exechange = "logs_direct"; //创建交换机类型是direct
channel.exchangeDeclare(exechange,"direct");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机,指明路由id
channel.queueBind(queue,exechange,"info");
channel.queueBind(queue,exechange,"warning");
channel.queueBind(queue,exechange,"error"); //消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1: "+new String(body));
}
});
}
}

消费者2

public class Consumer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitmqUtil.getConnection();
Channel channel = connection.createChannel(); String exechange = "logs_direct"; //创建交换机类型是direct
channel.exchangeDeclare(exechange,"direct");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机,指明路由id channel.queueBind(queue,exechange,"error"); //消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2: "+new String(body));
}
});
}
}

第五种模型(Topic)

Topic模型的Exchange与Direct相比,是可以根据RoutingKey的不同把消息路由到不同的队列。只不过Topic类型的Exchange可以让队列在绑定路由key的时候使用通配符,这种模型的路由key一般都是由一个或多个单词组成,多个单词之间以“.”分割。

# 通配符
* 表示可以匹配一个单词
\# 表示可以匹配一个或多个单词
例如:user.\# 可以代表user.login或者user.logout ,user.register.check等 user.* 表示user.login;user.lgout但是不能表示user.register.check

生产者

public class Provider {

    public static void main(String[] args) throws IOException {
// 获取连接对象
Connection connection = RabbitmqUtil.getConnection();
// 创建通信管道
Channel channel = connection.createChannel();
// 交换器名称
String exechange = "topics";
channel.exchangeDeclare(exechange,"topic");
// 指定路由key
String router_key = "response.error";
// 向交换器发送消息
channel.basicPublish(exechange,router_key,
null,("这是基于topic模型发布的 route_key="+router_key+" 发送的消息").getBytes());
RabbitmqUtil.closeConnAndChannel(channel,connection);
} }

消费者1

public class Consumer1 {

    public static void main(String[] args) throws IOException {
Connection connection = RabbitmqUtil.getConnection();
Channel channel = connection.createChannel(); String exechange = "topics"; //创建交换机类型是direct
channel.exchangeDeclare(exechange,"topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机,指明路由id
channel.queueBind(queue,exechange,"response.*"); //消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1: "+new String(body));
}
});
}
}

消费者2


public class Consumer2 { public static void main(String[] args) throws IOException {
Connection connection = RabbitmqUtil.getConnection();
Channel channel = connection.createChannel(); String exechange = "topics"; //创建交换机类型是direct
channel.exchangeDeclare(exechange,"topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机,指明路由id
channel.queueBind(queue,exechange,"response.#"); //消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1: "+new String(body));
}
});
}
}

运行结果

路由key改为response.error.code

RabbitMQ常用的几种消息模型的更多相关文章

  1. RabbitMQ之五种消息模型

    首先什么是MQ MQ全称是Message Queue,即消息对列!消息队列是典型的:生产者.消费者模型.生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的生产和消费都是异步的,而 ...

  2. rabbitmq五种消息模型整理

    目录 0. 配置项目 1. 基本消息模型 1.1 生产者发送消息 1.2 消费者获取消息(自动ACK) 1.3 消息确认机制(ACK) 1.4 消费者获取消息(手动ACK) 1.5 自动ACK存在的问 ...

  3. RabbitMQ,RocketMQ,Kafka 消息模型对比分析

    消息模型 消息队列的演进 消息队列模型 发布订阅模型 RabbitMQ的消息模型 交换器的类型 direct topic fanout headers Kafka的消息模型 RocketMQ的消息模型 ...

  4. JMS两种消息模型

    前段时间学习EJB.接触到了JMS(Java消息服务),JMS支持两种消息模型:Point-to-Point(P2P)和Publish/Subscribe(Pub/Sub),即点对点和公布订阅模型. ...

  5. SpringBoot 整合 RabbitMQ(包含三种消息确认机制以及消费端限流)

    目录 说明 生产端 消费端 说明 本文 SpringBoot 与 RabbitMQ 进行整合的时候,包含了三种消息的确认模式,如果查询详细的确认模式设置,请阅读:RabbitMQ的三种消息确认模式 同 ...

  6. SpringCloud(六) - RabbitMQ安装,三种消息发送模式,消息发送确认,消息消费确认(自动,手动)

    1.安装erlang语言环境 1.1 创建 erlang安装目录 mkdir erlang 1.2 上传解压压缩包 上传到: /root/ 解压缩# tar -zxvf otp_src_22.0.ta ...

  7. RabbitMQ除开RPC的五种消模型----原生API

    2.五种消息模型 RabbitMQ提供了6种消息模型,但是第6种其实是RPC,并不是MQ,因此不予学习.那么也就剩下5种. 但是其实3.4.5这三种都属于订阅模型,只不过进行路由的方式不同. 通过一个 ...

  8. Kafka消息模型

    一.消息传递模型 传统的消息队列最少提供两种消息模型,一种P2P,一种PUB/SUB,而Kafka并没有这么做,巧妙的,它提供了一个消费者组的概念,一个消息可以被多个消费者组消费,但是只能被一个消费者 ...

  9. HTTPD三种工作模型

    HTTPD三种工作模型 MPM是apache的多道处理模块,用于定义apache对客户端请求的处理方式.在linux中apache常用的三种MPM模型分别是prefork.worker和event. ...

随机推荐

  1. 题解-CF436E Cardboard Box

    题面 CF436E Cardboard Box \(n\) 个关卡,对每个关卡可以花 \(a_i\) 时间得到 \(1\) 颗星,或花 \(b_i\) 时间得到 \(2\) 颗星,或不玩.问获得 \( ...

  2. MVC部署出现403.14问题记录

    1.问题截图 2.解决办法有几种 1)在system.webServer下增加,这种是不推荐的. <modules runAllManagedModulesForAllRequests=&quo ...

  3. modelViewSet 获取未序列化的数据

    1 views/  perform_create 方法的使用  获取未序列化的数据 def perform_create(self, serializer): user_obj=serializer. ...

  4. mycat配置MySQL主从读写分离

    1.安装java 1.8 mycat 1.6要求的Java需要Java 1.8或1.8以上,安装Java参考以下链接: https://blog.csdn.net/weixin_43893397/ar ...

  5. 如何在 Windows 10 上安装 WSL 2

    翻译自 Joey Sneddon 2020年10月30日的文章<How to Install WSL 2 on Windows 10> [1] 如果您想在最新的 Windows 版本中尝试 ...

  6. CI/CD持续集成方案

    一,CI/CD流程和持续交付简介 CI(Continuous Integration)持续集成  CD(Continuous Deployment)持续部署  CD(Continuous delive ...

  7. db2常用操作

    1. db2建立远程节点编目及删除 db2 catalog tcpip node nodeName remote remoteIp server remotePort db2 list node di ...

  8. Python高级语法-对象实例对象属性-类与实例,class方法静态方法等(4.6.1)

    @ 目录 1.说明 2.代码 关于作者 1.说明 python中属性:类属性,实例属性 方法:类方法,实例方法,静态方法 想修改类属性,只能是类方法,因为只有类方法把cls(类)传入数据里面 静态方法 ...

  9. CCNP之MERG实验报告

    MGRE实验报告 一.实验要求: 1.R5为ISP,只能配置IP地址 2.R1--R3间建立MGRE环境,且使用EIGRP来学习各自环回 3.R4可以正常访问R5的环回 4.R1与R5进行chap认证 ...

  10. 使用Ubuntu手动安装NextCloud

    p.p1 { margin: 0; font: 11px Menlo; color: rgba(0, 0, 0, 1) } span.s1 { font-variant-ligatures: no-c ...