RabbitMQ五种工作模式

HelloWorld 简单模式

WorkQueues 工作队列模式

Publish/Subscribe 发布/订阅模式

Routing 路由模式

Topic 通配符模式

五大模式总结

一、HelloWorld 简单模式

1.创建Maven工程(我用的IDEA)

File[文件] -> New[新建] -> Project[工程] -> Maven[选择Maven] -> Next[直接下一步] -> Name[输入项目名称] —> Finish[完成]

2.在项目里创建两个子工程

Producer 消息生产者

项目名称位置右键 -> New[新建] -> Module[组件] -> Maven[选择Maven] -> Next[下一步] -> Name[输入Producer] —> Finish[完成]

Consumer 消息消费者

项目名称位置右键 -> New[新建] -> Module[组件] -> Maven[选择Maven] -> Next[下一步] -> Name[输入Consumer] —> Finish[完成]

3.在主项目工程的pom文件里填写依赖(注意是主项目 两个子项目会继承父项目的依赖)

<dependencies>
<!--com.rabbitmq:amqp-client RabbitMq依赖 [重要]-->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.3</version>
</dependency> <!--下面三个依赖是为了方便控制台输出Log [一般]-->
<!--junit:junit 单元测试框架 用了都说好-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency> <!--org.projectlombok:lombok 整合注解-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency> <!--ch.qos.logback:logback-classic 日志框架-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>

4.编写生产者

4.1.在Producer项目里创建Java类文件

src/main/java/包名*/ProducerApplication.java

4.2.撸码(具体看注释)

 import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 简单模式 生产者
* @author Admin
*/
@Slf4j
public class ProducerApplication { //定义Queue队列的名称
private final static String SIMPLE_QUEUE = "simple"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 生产者
*/
@Test
public void testSend(){
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
/*
* channel.queueDeclare();
* Param1: 队列名称
* Param2: 是否持久化
* Param3: 是否具有独占性
* Param4: 是否自动删除队列
* Param5: 具体参数
*/
channel.queueDeclare(SIMPLE_QUEUE,true,false,false,null);
//发布信息到队列
String message = "简单模式 —> 发送第1条信息";
channel.basicPublish("",SIMPLE_QUEUE, null, message.getBytes());
log.debug("发送信息成功"); //关闭资源
channel.close();
connection.close();
} catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

5.编写消费者

5.1.在Consumer项目里创建Java类文件

src/main/java/包名*/ConsumerApplication.java

5.2.撸码(重点看注解)

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 简单模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication { //定义Queue队列的名称
private final static String SIMPLE_QUEUE = "simple"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
//回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(SIMPLE_QUEUE,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

二、WorkQueues 工作队列模式

知识点:Work Queues与入门程序的简单模式的代码是几乎一样的;可以完全复制,并复制多一个消费者进行多个消费者同时消费消息的测试。

1 - 3步与简单模式一致

过去看看

4.编写生产者

4.1.在Producer项目里创建Java类文件

src/main/java/包名*/ProducerApplication.java

4.2.撸码(具体看注释)

 import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 简单模式 生产者
* @author Admin
*/
@Slf4j
public class ProducerApplication { //定义Queue队列的名称
private final static String WORK_QUEUE = "work_queue"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 生产者
*/
@Test
public void testSend(){
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
/*
* channel.queueDeclare();
* Param1: 队列名称
* Param2: 是否持久化
* Param3: 是否具有独占性
* Param4: 是否自动删除队列
* Param5: 具体参数
*/
channel.queueDeclare(WORK_QUEUE,true,false,false,null);
//发布信息到队列
for (int i = 1; i <= 20; i++){
String message = "工作队列模式 —> 发送第" + i + "条信息";
channel.basicPublish("",WORK_QUEUE, null, message.getBytes());
}
log.debug("发送信息成功");
//关闭资源
channel.close();
connection.close();
} catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

5.编写消费者

5.1.在Consumer项目里创建Java类文件

src/main/java/包名*/ConsumerApplication01.java

src/main/java/包名*/ConsumerApplication02.java

5.2.撸码(重点看注解)

消费者01

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 工作队列模式 消费者01
* @author Admin
*/
@Slf4j
public class ConsumerApplication01 { //定义Queue队列的名称
private final static String WORK_QUEUE = "work_queue"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel(); //一次只能接收并处理一个消息
channel.basicQos(1); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
try {
//消费者01 模拟延迟1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//消息消费完后自动确认发送到MQ
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
}; channel.basicConsume(WORK_QUEUE,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

消费者02

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 工作队列模式 消费者02
* @author Admin
*/
@Slf4j
public class ConsumerApplication02 { //定义Queue队列的名称
private final static String WORK_QUEUE = "work_queue"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel(); //一次只能接收并处理一个消息
channel.basicQos(1); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
try {
//消费者02 模拟延迟2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//消息消费完后自动确认发送到MQ
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
}; channel.basicConsume(WORK_QUEUE,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

6.测试

先运行两个消费者,在启动生产者

7.小结

一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系。

三、Publish/Subscribe 发布/订阅模式

知识点:

1、每个消费者监听自己的队列。

2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息

1 - 3步与简单模式一致

过去看看

4.编写生产者

4.1.在Producer项目里创建Java类文件

src/main/java/包名*/ProducerApplication.java

4.2.撸码(具体看注释)

 import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 发布订阅模式 生产者
* @author Admin
*/
@Slf4j
public class ProducerApplication { //交换机名称
static final String FANOUT_EXCHANGE = "fanout_exchange";
//队列名称
static final String FANOUT_QUEUE_1 = "fanout_queue_1";
//队列名称
static final String FANOUT_QUEUE_2 = "fanout_queue_2"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 生产者
*/
@Test
public void testSend(){
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
/**
* 声明交换机
* 参数1:交换机名称
* 参数2:交换机类型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT); // 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(FANOUT_QUEUE_1, true, false, false, null);
channel.queueDeclare(FANOUT_QUEUE_2, true, false, false, null);
//发布信息到队列
for (int i = 1; i <= 20; i++){
String message = "发布订阅模式 —> 发送第" + i + "条信息";
channel.basicPublish(FANOUT_EXCHANGE, "", null, message.getBytes());
}
log.debug("发送信息成功");
//关闭资源
channel.close();
connection.close();
} catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

5.编写消费者

5.1.在Consumer项目里创建Java类文件

src/main/java/包名*/ConsumerApplication01.java

src/main/java/包名*/ConsumerApplication02.java

5.2.撸码(重点看注解)

消费者01

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 简单模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication01 { //交换机名称
static final String FANOUT_EXCHANGE = "fanout_exchange";
//队列名称
static final String FANOUT_QUEUE_1 = "fanout_queue_1"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(Producer.FANOUT_QUEUE_1, true, false, false, null); //队列绑定交换机
channel.queueBind(FANOUT_QUEUE_1, FANOUT_EXCHANGE, ""); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(FANOUT_QUEUE_1,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

消费者02

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 简单模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication02 { //交换机名称
static final String FANOUT_EXCHANGE = "fanout_exchange";
//队列名称
static final String FANOUT_QUEUE_2 = "fanout_queue_2"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(Producer.FANOUT_QUEUE_2, true, false, false, null); //队列绑定交换机
channel.queueBind(FANOUT_QUEUE_2, FANOUT_EXCHANGE, ""); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(FANOUT_QUEUE_2,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

6.测试

启动所有消费者,然后使用生产者发送消息;在每个消费者对应的控制台可以查看到生产者发送的所有消息;到达广播的效果。

7.小结

发布订阅模式与工作队列模式的区别

1、工作队列模式不用定义交换机,而发布/订阅模式需要定义交换机。

2、发布/订阅模式的生产方是面向交换机发送消息,工作队列模式的生产方是面向队列发送消息(底层使用默认交换机)。

3、发布/订阅模式需要设置队列和交换机的绑定,工作队列模式不需要设置,实际上工作队列模式会将队列绑 定到默认的交换机。

四、Routing 路由模式

知识点:

1. 队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)

2. 息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey

3. Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息

1 - 3步与简单模式一致

过去看看

4.编写生产者

4.1.在Producer项目里创建Java类文件

src/main/java/包名*/ProducerApplication.java

4.2.撸码(具体看注释)

 import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 路由模式 生产者
* @author Admin
*/
@Slf4j
public class ProducerApplication { //交换机名称
static final String DIRECT_EXCHANGE = "direct_exchange";
//队列名称
static final String DIRECT_QUEUE_INSERT = "direct_queue_insert";
//队列名称
static final String DIRECT_QUEUE_UPDATE = "direct_queue_update"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 生产者
*/
@Test
public void testSend(){
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
/**
* 声明交换机
* 参数1:交换机名称
* 参数2:交换机类型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT); // 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null);
channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null);
//队列绑定交换机 channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert");
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update"); //发布信息到队列
String insert = "路由模式发布消息 Routing为:insert";
channel.basicPublish(DIRECT_EXCHANGE, "insert", null, insert.getBytes());
String update = "路由模式发布消息 Routing为:update";
channel.basicPublish(DIRECT_EXCHANGE, "update", null, update.getBytes()); log.debug("发送信息成功");
//关闭资源
channel.close();
connection.close();
} catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

5.编写消费者

5.1.在Consumer项目里创建Java类文件

src/main/java/包名*/ConsumerApplication01.java

src/main/java/包名*/ConsumerApplication02.java

5.2.撸码(重点看注解)

消费者01

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 路由模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication01 { //交换机名称
static final String DIRECT_EXCHANGE = "direct_exchange";
//队列名称
static final String DIRECT_QUEUE_INSERT = "direct_queue_insert"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null); //队列绑定交换机
channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert"); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(DIRECT_QUEUE_INSERT,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

消费者02

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 路由模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication02 { //交换机名称
static final String DIRECT_EXCHANGE = "direct_exchange";
//队列名称
static final String DIRECT_QUEUE_UPDATE = "direct_queue_update"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null); //队列绑定交换机
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "insert"); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(DIRECT_QUEUE_UPDATE,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

6.测试

启动所有消费者,然后使用生产者发送消息;在消费者对应的控制台可以查看到生产者发送对应routing key对应队列的消息;到达按照需要接收的效果。

7.小结

Routing模式要求队列在绑定交换机时要指定routing key,消息会转发到符合routing key的队列。

五、Topic 通配符模式

知识点:

1. Topic类型与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符

2. Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert

3. 通配符规则:

#:匹配一个或多个词

*:匹配不多不少恰好1个词

1 - 3步与简单模式一致

过去看看

4.编写生产者

4.1.在Producer项目里创建Java类文件

src/main/java/包名*/ProducerApplication.java

4.2.撸码(具体看注释)

 import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 发布订阅模式 生产者
* @author Admin
*/
@Slf4j
public class ProducerApplication { //交换机名称
static final String TOPIC_EXCHANGE = "topic_exchange";
//队列名称
static final String TOPIC_QUEUE_1 = "topic_queue_1";
//队列名称
static final String TOPIC_QUEUE_2 = "topic_queue_2"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 生产者
*/
@Test
public void testSend(){
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
/**
* 声明交换机
* 参数1:交换机名称
* 参数2:交换机类型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC); //发布信息到队列
String insert = "路由模式发布消息 Routing为:item.insert";
channel.basicPublish(TOPIC_EXCHANGE, "item.insert", null, insert.getBytes());
String update = "路由模式发布消息 Routing为:item.update";
channel.basicPublish(TOPIC_EXCHANGE, "item.update", null, update.getBytes());
String update = "路由模式发布消息 Routing为:item.delete";
channel.basicPublish(TOPIC_EXCHANGE, "item.delete", null, update.getBytes()); log.debug("发送信息成功");
//关闭资源
channel.close();
connection.close();
} catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

5.编写消费者

5.1.在Consumer项目里创建Java类文件

src/main/java/包名*/ConsumerApplication01.java

src/main/java/包名*/ConsumerApplication02.java

5.2.撸码(重点看注解)

消费者01

   import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* RabbitMQ - 通配符模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication01 { //交换机名称
static final String TOPIC_EXCHANGE = "topic_exchange";
//队列名称
static final String TOPIC_QUEUE_1 = "topic_queue_1"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(TOPIC_QUEUE_1, true, false, false, null); //队列绑定交换机
channel.queueBind(TOPIC_QUEUE_1, TOPIC_EXCHAGE, "item.update");
channel.queueBind(TOPIC_QUEUE_1, TOPIC_EXCHAGE, "item.delete"); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(TOPIC_QUEUE_1,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

消费者02

  import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* RabbitMQ - 通配符模式 消费者
* @author Admin
*/
@Slf4j
public class ConsumerApplication02 { //交换机名称
static final String TOPIC_EXCHANGE = "topic_exchange";
//队列名称
static final String TOPIC_QUEUE_2 = "topic_queue_2"; public static ConnectionFactory getFactory(){
//设置连接工程
ConnectionFactory factory = new ConnectionFactory();
//设置 host
factory.setHost("localhost");
//设置 port 默认为5672
factory.setPort(5672);
//设置 virtualHost
factory.setVirtualHost("/");
//设置 账号和密码
factory.setUsername("username");
factory.setPassword("password");
return factory;
} /**
* 消费者
*/
public static void main(String[] args) {
try {
//创建连接对象
Connection connection = getFactory().newConnection();
//创建信道对象
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* 参数1:队列名称
* 参数2:是否定义持久化队列
* 参数3:是否独占本次连接
* 参数4:是否在不使用的时候自动删除队列
* 参数5:队列其它参数
*/
channel.queueDeclare(TOPIC_QUEUE_2, true, false, false, null); //队列绑定交换机
channel.queueBind(TOPIC_QUEUE_2, TOPIC_EXCHAGE, "item.update");
channel.queueBind(TOPIC_QUEUE_2, TOPIC_EXCHAGE, "item.delete"); //回调方法
DeliverCallback deliverCallback = (consumerTag,delivery) -> {
//接受信息到队列
String message = new String(delivery.getBody(),"UTF-8");
log.info(" [√] 接受到消息:"+message);
}; channel.basicConsume(TOPIC_QUEUE_2,true,deliverCallback,consumerTag ->{}); //consumer不关闭channel 和 connection 因为要一直监视消息 } catch (IOException e) {
log.error("[IOException]发现错误 发送信息失败:{}", e.getMessage());
} catch (TimeoutException e) {
log.error("[TimeoutException]发现错误 发送信息失败:{}", e.getMessage());
}
}
}

6.测试

启动所有消费者,然后使用生产者发送消息;在消费者对应的控制台可以查看到生产者发送对应routing key对应队列的消息;到达按照需要接收的效果;并且这些routing key可以使用通配符。

7.小结

Topic主题模式可以实现 Publish/Subscribe发布与订阅模式 Routing路由模式 的功能;只是Topic在配置routing key 的时候可以使用通配符,显得更加灵活。

RabbitMQ工作模式总结

一、简单模式 HelloWorld

一个生产者、一个消费者,不需要设置交换机(使用默认的交换机)

二、工作队列模式 Work Queue

一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认的交换机)

三、发布订阅模式 Publish/subscribe

需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列

四、路由模式 Routing

需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列

五、通配符模式 Topic

需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列

RabbitMq 初学五大模式 通俗易懂 超详细 【包含案例】的更多相关文章

  1. RabbitMQ安装说明文档(超详细版本)

    RabbitMQ安装说明文档(超详细版本) 1. 安装依赖环境 在线安装依赖环境: yum install build-essential openssl openssl-devel unixODBC ...

  2. 超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用)

    超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用) 转载自:https://www.jianshu.com/p/2ad8c8b5bf75 亲测有效~ <tem ...

  3. 超强、超详细Redis数据库入门教程

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...

  4. GitHub超详细图文攻略

    GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git 分类: 转载2014-03-25 21:10 10641人阅读 评论(2) 收藏 举报 GitHubbr ...

  5. 超全超详细的HTTP状态码大全(推荐抓包工具HTTP Analyzer V6.5.3)

    超全超详细的HTTP状态码大全 本部分余下的内容会详细地介绍 HTTP 1.1中的状态码.这些状态码被分为五大类: 100-199 用于指定客户端应相应的某些动作. 200-299 用于表示请求成功. ...

  6. 超强、超详细Redis数据库入门教程(转载)

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下   [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...

  7. NumPy 超详细教程(3):ndarray 的内部机理及高级迭代

    系列文章地址 NumPy 最详细教程(1):NumPy 数组 NumPy 超详细教程(2):数据类型 NumPy 超详细教程(3):ndarray 的内部机理及高级迭代 ndarray 对象的内部机理 ...

  8. Linux 学习笔记之超详细基础linux命令 Part 9

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 8----------------- ...

  9. 转帖: 一份超全超详细的 ADB 用法大全

    增加一句 连接 网易mumu模拟器的方法 adb  connect 127.0.0.1:7555 一份超全超详细的 ADB 用法大全 2016年08月28日 10:49:41 阅读数:35890 原文 ...

  10. (转)Springboot日志配置(超详细,推荐)

    Spring Boot-日志配置(超详细) 更新日志: 20170810 更新通过 application.yml传递参数到 logback 中. Spring Boot-日志配置超详细 默认日志 L ...

随机推荐

  1. python 将查询到数据,处理成包含列名和数据的字典类型数据

    try: self.connect_dbserver() self.cursor.execute(sql) res = self.cursor.fetchall() # 返回的是数组的类型 print ...

  2. RHEL8.1---离线升级gcc

    升级gcc到gcc9.1.0 下载离线包.放到/opt下 [root@172-18-251-35 opt]# wget http://ftp.gnu.org/gnu/gcc/gcc-9.1.0/gcc ...

  3. Codeforces Round #243 (Div. 2) Problem B - Sereja and Mirroring 题解

    http://codeforces.com/contest/426/problem/B 题意大概就是对称有关,要注意的是,当行数为奇数的时候,答案就是行数本身 #include<iostream ...

  4. Mysql 使用(一)

    一.数据库的种类 关系型数据库 非关系型数据库 二.常见关系型数据库 oracle:在以前的大型项目中使用,银行,电信等项目 mysql:web时代使用最广泛的关系型数据库 ms sql server ...

  5. HDOJ 6703 Array

    HDOJ 6703 Array 题目 题目链接 array *Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K ...

  6. 在Linux驱动中使用notifier通知链

    在Linux驱动中使用notifier通知链 背景 在驱动分析中经常看到fb_notifier_callback,现在趁有空学习一下. 介绍 linux中的观察者模式是最显然的就是"通知链& ...

  7. arm linux 移植 curl

    背景 libcurl是一个跨平台的开源网络协议库,支持http, https, rtsp等多种协议 .libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传, ...

  8. sqlite相关

    前言 本文记录一些sqlite相关笔记,随时更新. 正文 时间函数 datetime() -- 当前时间 2022-03-24 17:32:43 select datetime('now'); --2 ...

  9. Linux常用指令及shell脚本记录

    记录一些常用指令在博客上,以防哪天因太久不敲而忘却,还可以直接翻看博客记录,不用再一条条百度搜...... 一.Linux常用指令 一.设置文件权限为aapp用户及用户组-- chown -R app ...

  10. 全网最适合入门的面向对象编程教程:10 类和对象的 Python 实现-类的继承和里氏替换原则,Python 模拟主机和传感器自定义类

    全网最适合入门的面向对象编程教程:10 类和对象的 Python 实现-类的继承和里氏替换原则,Python 模拟主机和传感器自定义类 摘要: 本文主要介绍了类的继承的基本概念和里氏替换原则,以模拟传 ...