RabbitMQ的应用

7种工作模式介绍

下述代码中要在pom文件中引入依赖

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

Simple(简单模式)

在这里插入图片描述
P: ⽣产者, 也就是要发送消息的程序
C: 消费者,消息的接收者
Queue: 消息队列, 图中⻩⾊背景部分. 类似⼀个邮箱, 可以缓存消息; ⽣产者向其中投递消息, 消费者从其中取出消息.
特点: ⼀个⽣产者P,⼀个消费者C, 消息只能被消费⼀次. 也称为点对点(Point-to-Point)模式.
生产者代码在上一期可以看到

Work Queue(⼯作队列)

⼀个⽣产者P,多个消费者C1,C2. 在多个消息的情况下, Work Queue 会将消息分派给不同的消费者, 每个消费者都会接收到不同的消息.
特点: 消息不会重复, 分配给不同的消费者.
适⽤场景: 集群环境中做异步处理
在这里插入图片描述
先声明一个全局变量初始化

public class Constants {
public static final String H0ST = "110.41.51.65";
public static final Integer PORT = 15673;
public static final String VIRTUAL_HOST = "bite";
public static final String USER_NAME = "study";
public static final String PASSwORD = "study";
public static final String WORK_QUEUE_NAME = "work_queues";

然后在创建一个生产者

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import constant.Constants;
public class WorkRabbitProducer {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 声明队列
 //如果没有⼀个这样的⼀个队列, 会⾃动创建, 如果有, 则不创建
 channel.queueDeclare(Constants.WORK_QUEUE_NAME, true, false, false, 
null);
 //3. 发送消息
 for (int i = 0; i < 10; i++) {
 String msg = "Hello World" + i;
 
channel.basicPublish("",Constants.WORK_QUEUE_NAME,null,msg.getBytes());
 }
 //4. 释放资源
 channel.close();
 connection.close();
 }
 }

再次创建一个消费者代码

import com.rabbitmq.client.*;
import constant.Constants;
import java.io.IOException;
public class WorkRabbitmqConsumer1 {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 声明队列
 //如果没有⼀个这样的⼀个队列, 会⾃动创建, 如果有, 则不创建
 channel.queueDeclare(Constants.WORK_QUEUE_NAME, true, false, false, 
null);
 //3. 接收消息, 并消费
 DefaultConsumer consumer = new DefaultConsumer(channel) {
 @Override
 public void handleDelivery(String consumerTag, Envelope envelope, 
AMQP.BasicProperties properties, byte[] body) throws IOException {
 System.out.println("接收到消息: " + new String(body));
 }
 };
 channel.basicConsume(Constants.WORK_QUEUE_NAME, true, consumer);
 }
 }

在这里插入图片描述

Publish/Subscribe(发布/订阅)

在这里插入图片描述
Exchange: 交换机 (X).
作⽤: ⽣产者将消息发送到Exchange, 由交换机将消息按⼀定规则路由到⼀个或多个队列中(上图中⽣产者将消息投递到队列中, 实际上这个在RabbitMQ中不会发⽣. )
RabbitMQ交换机有四种类型: fanout,direct, topic, headers, 不同类型有着不同的路由策略. AMQP协议⾥还有另外两种类型, System和⾃定义, 此处不再描述.

  1. Fanout:⼴播,将消息交给所有绑定到交换机的队列(Publish/Subscribe模式)
  2. Direct:定向,把消息交给符合指定routing key的队列(Routing模式)
  3. Topic:通配符,把消息交给符合routing pattern(路由模式)的队列(Topics模式)
  4. headers类型的交换器不依赖于路由键的匹配规则来路由消息, ⽽是根据发送的消息内容中的headers属性进⾏匹配. headers类型的交换器性能会很差,⽽且也不实⽤,基本上不会看到它的存在.
    Exchange(交换机)只负责转发消息, 不具备存储消息的能⼒, 因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失
    RoutingKey: 路由键.⽣产者将消息发给交换器时, 指定的⼀个字符串, ⽤来告诉交换机应该如何处理这个消息.
    Binding Key:绑定. RabbitMQ中通过Binding(绑定)将交换器与队列关联起来, 在绑定的时候⼀般会指定⼀个Binding Key, 这样RabbitMQ就知道如何正确地将消息路由到队列了.
    在这里插入图片描述
    在这里插入图片描述1.在使用绑定的时候,需要的路由键是BindingKey.
    2.在发送消息的时候,需要的路由键是RoutingKey.
    本课程后续也可能把两者合称为RoutingKey,大家根据使用场景来区分.

代码中用全局声明

public static String FANOUT_EXCHANGE_NAME = "test_fanout";
public static String FANOUT_QUEUE_NAME1 = "fanout_queue1";
public static String FANOUT_QUEUE_NAME2 = "fanout_queue2

生产者代码

public class FanoutRabbitProducer {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 创建交换机
 /*
 exchangeDeclare(String exchange, BuiltinExchangeType type, boolean 
durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
 参数:
 1. exchange:交换机名称
 2. type:交换机类型
 * DIRECT("direct"), 定向,直连,routing
 * * FANOUT("fanout"),扇形(⼴播), 每个队列都能收到消息
 * TOPIC("topic"),通配符
 * HEADERS("headers") 参数匹配(⼯作⽤的较少)
 3. durable: 是否持久化
 4. autoDelete: ⾃动删除
 5. internal: 内部使⽤, ⼀般falase
 6. arguments: 参数
 */
 channel.exchangeDeclare(Constants.FANOUT_EXCHANGE_NAME, 
BuiltinExchangeType.FANOUT, true, false, false, null);
 //3. 声明队列
 //如果没有⼀个这样的⼀个队列, 会⾃动创建, 如果有, 则不创建
 channel.queueDeclare(Constants.FANOUT_QUEUE_NAME1, true, false, false, 
null);
 channel.queueDeclare(Constants.FANOUT_QUEUE_NAME2, true, false, false, 
null);
 //4. 绑定队列和交换机
 /*
 queueBind(String queue, String exchange, String routingKey, 
Map<String, Object> arguments)
 参数:
 1. queue: 队列名称
 2. exchange: 交换机名称
 3. routingKey: 路由key, 路由规则
 如果交换机类型为fanout,routingkey设置为"",表⽰每个消费者都可以收到全部信息
 */
 
channel.queueBind(Constants.FANOUT_QUEUE_NAME1,Constants.FANOUT_EXCHANGE_NAME, 
"");
 
channel.queueBind(Constants.FANOUT_QUEUE_NAME2,Constants.FANOUT_EXCHANGE_NAME, 
"");
 //5. 发送消息
 /**
 * basicPublish(String exchange, String routingKey, 
AMQP.BasicProperties props, byte[] body)
 * 参数说明:
 * Exchange: 交换机名称
 * routingKey: 如果交换机类型为fanout,routingkey设置为"",表⽰每个消费者都可以
收到全部信息
 */
 String msg = "hello fanout";
 
channel.basicPublish(Constants.FANOUT_EXCHANGE_NAME,"",null,msg.getBytes());
channel.close();
 connection.close();
 }
 }

消费者代码

import com.rabbitmq.client.*;
import constant.Constants;
import java.io.IOException;
public class FanoutRabbitmqConsumer1 {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 接收消息, 并消费
 DefaultConsumer consumer = new DefaultConsumer(channel) {
 @Override
 public void handleDelivery(String consumerTag, Envelope envelope, 
AMQP.BasicProperties properties, byte[] body) throws IOException {
 System.out.println("接收到消息: " + new String(body));
 }
 };
 channel.basicConsume(Constants.FANOUT_QUEUE_NAME1, true, consumer);
 }

在这里插入图片描述
在这里插入图片描述

Routing(路由模式)

在这里插入图片描述
路由模式是发布订阅模式的变种, 在发布订阅基础上, 增加路由key
发布订阅模式是⽆条件的将所有消息分发给所有消费者, 路由模式是Exchange根据RoutingKey的规则,将数据筛选后发给对应的消费者队列
适合场景: 需要根据特定规则分发消息的场景
生产者代码
创建交换机

channel.exchang
BuiltinExchangeType.DIRECT, true,false,,false, null);

声明队列

channel.queueDeclare(Constants.DIRECT_QUEUE_NAME1, true, false, false, null);
channel.queueDeclare(Constants.DIRECT_QUEUE_NAME2, true, false, false, null);

绑定交换机和队列

//队列1绑定orange
channel.queueBind(Constants.DIRECT_QUEUE_NAME1,Constants.DIRECT_EXCHANGE_NAME,
"orange");
//队列2绑定black,green
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME,
"black");
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME,
green

发送消息

//发送消息时,指定RoutingKey
String msg = "hello direct, I am orange";
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"orange",null, msg·getBytes(
));
String msg_black = "hello direct,I am black";
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"black", null,msg_black.getB
ytes());
String msg-green= "hello direct, I am green";
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"green", nuLl,msg-green.getB
ytes());

声明交换机和队列

public static String DIRECT_EXCHANGE_NAME = "test_direct";
public static String DIRECT_QUEUE_NAME1 = "direct_queue1";
public static String DIRECT_QUEUE_NAME2 = "direct_queue2";

生产者代码

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import constant.Constants;
public class DirectRabbitProducer {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 创建交换机
 channel.exchangeDeclare(Constants.DIRECT_EXCHANGE_NAME, 
BuiltinExchangeType.FANOUT, true, false, false, null);
 //3. 声明队列
 //如果没有⼀个这样的⼀个队列, 会⾃动创建, 如果有, 则不创建
 channel.queueDeclare(Constants.DIRECT_QUEUE_NAME1, true, false, false, 
null);
 channel.queueDeclare(Constants.DIRECT_QUEUE_NAME2, true, false, false, 
null);
//4. 绑定队列和交换机
 //队列1绑定orange
 
channel.queueBind(Constants.DIRECT_QUEUE_NAME1,Constants.DIRECT_EXCHANGE_NAME, 
"orange");
 //队列2绑定black, green
 
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME, 
"black");
 
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME, 
"green");
 //5. 发送消息
 String msg = "hello direct, I am orange";
 
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"orange",null,msg.getBytes(
));
 String msg_black = "hello direct,I am black";
 
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"black",null,msg_black.getB
ytes());
 String msg_green= "hello direct, I am green";
 
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"green",null,msg_green.getB
ytes());
 //6.释放资源
 channel.close();
 connection.close();
 }
 }

消费者代码

mport com.rabbitmq.client.*;
import constant.Constants;
import java.io.IOException;
public class DirectRabbitmqConsumer1 {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 接收消息, 并消费
 DefaultConsumer consumer = new DefaultConsumer(channel) {
 @Override
 public void handleDelivery(String consumerTag, Envelope envelope, 
AMQP.BasicProperties properties, byte[] body) throws IOException {
 System.out.println("接收到消息: " + new String(body));
 }
 };
 channel.basicConsume(Constants.DIRECT_QUEUE_NAME1, true, consumer);
 }
 }

在这里插入图片描述
在这里插入图片描述

Topics(通配符模式)

在这里插入图片描述
路由模式的升级版, 在routingKey的基础上,增加了通配符的功能, 使之更加灵活.
Topics和Routing的基本原理相同,即:⽣产者将消息发给交换机,交换机根据RoutingKey将消息转发给与RoutingKey匹配的队列. 类似于正则表达式的⽅式来定义Routingkey的模式.
RoutingKey 是⼀系列由点( . )分隔的单词, ⽐如 " stock.usd.nyse “, " nyse.vmw “,
" quick.orange.rabbit "
2. BindingKey 和RoutingKey⼀样, 也是点( . )分割的字符串.
3. Binding Key中可以存在两种特殊字符串, ⽤于模糊匹配
* 表⽰⼀个单词
# 表⽰多个单词(0-N个)
⽐如:
• Binding Key 为"d.a.b” 会同时路由到Q1 和Q2
• Binding Key 为"d.a.f” 会路由到Q1
• Binding Key 为"c.e.f" 会路由到Q2
• Binding Key 为"d.b.f" 会被丢弃, 或者返回给⽣产者(需要设置mandatory参数)
不同之处是:routingKey的匹配⽅式不同,Routing模式是相等匹配,topics模式是通配符匹配.
适合场景: 需要灵活匹配和过滤消息的场景
生产者代码

public static String TOPIC_EXCHANGE_NAME = "test_topic";
public static String TOPIC_QUEUE_NAME1 = "topic_queue1";
public static String TOPIC_QUEUE_NAME2 = "topic_queue2";
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import constant.Constants;
public class TopicRabbitProducer {
 public static void main(String[] args) throws Exception {
 //1. 创建channel通道
 ConnectionFactory factory = new ConnectionFactory();
 factory.setHost(Constants.HOST);//ip 默认值localhost
 factory.setPort(Constants.PORT); //默认值5672
 factory.setVirtualHost(Constants.VIRTUAL_HOST);//虚拟机名称, 默认 /
 factory.setUsername(Constants.USER_NAME);//⽤⼾名,默认guest
 factory.setPassword(Constants.PASSWORD);//密码, 默认guest
 Connection connection = factory.newConnection();
 Channel channel = connection.createChannel();
 //2. 创建交换机
 channel.exchangeDeclare(Constants.TOPIC_EXCHANGE_NAME, 
BuiltinExc
RabbitMQ是一个开源的消息中间件,它可以用于实现应用程序之间的解耦。通过使用RabbitMQ应用程序可以通过发送和接收消息来进行通信,而不需要直接依赖于彼此的存在和状态。 以下是RabbitMQ应用解耦的一些常见场景和方法: 1. 发布/订阅模式:发布/订阅模式是一种常见的解耦方式,其中一个应用程序(发布者)将消息发送到RabbitMQ的交换机,而其他应用程序(订阅者)则从交换机订阅并接收消息。这样,发布者和订阅者之间不需要直接通信,它们只需要通过交换机进行消息传递。 2. 队列模式:队列模式是另一种常见的解耦方式,其中一个应用程序将消息发送到RabbitMQ的队列中,而其他应用程序则从队列中接收消息。这样,发送者和接收者之间不需要直接通信,它们只需要通过队列进行消息传递。 3. 路由模式:路由模式是一种更灵活的解耦方式,其中消息根据路由键被发送到不同的队列。发送者可以指定消息的路由键,而接收者可以根据路由键选择性地接收消息。这样,发送者和接收者之间可以根据需要进行灵活的消息传递。 4. 主题模式:主题模式是一种更高级的解耦方式,其中消息根据主题进行发布和订阅。发送者可以指定消息的主题,而接收者可以根据主题选择性地接收消息。这样,发送者和接收者之间可以根据主题进行灵活的消息传递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼裤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值