RabbitMq 初学五大模式 通俗易懂 超详细 【包含案例】
RabbitMQ五种工作模式
一、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 初学五大模式 通俗易懂 超详细 【包含案例】的更多相关文章
- RabbitMQ安装说明文档(超详细版本)
RabbitMQ安装说明文档(超详细版本) 1. 安装依赖环境 在线安装依赖环境: yum install build-essential openssl openssl-devel unixODBC ...
- 超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用)
超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用) 转载自:https://www.jianshu.com/p/2ad8c8b5bf75 亲测有效~ <tem ...
- 超强、超详细Redis数据库入门教程
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...
- GitHub超详细图文攻略
GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git 分类: 转载2014-03-25 21:10 10641人阅读 评论(2) 收藏 举报 GitHubbr ...
- 超全超详细的HTTP状态码大全(推荐抓包工具HTTP Analyzer V6.5.3)
超全超详细的HTTP状态码大全 本部分余下的内容会详细地介绍 HTTP 1.1中的状态码.这些状态码被分为五大类: 100-199 用于指定客户端应相应的某些动作. 200-299 用于表示请求成功. ...
- 超强、超详细Redis数据库入门教程(转载)
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...
- NumPy 超详细教程(3):ndarray 的内部机理及高级迭代
系列文章地址 NumPy 最详细教程(1):NumPy 数组 NumPy 超详细教程(2):数据类型 NumPy 超详细教程(3):ndarray 的内部机理及高级迭代 ndarray 对象的内部机理 ...
- Linux 学习笔记之超详细基础linux命令 Part 9
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 8----------------- ...
- 转帖: 一份超全超详细的 ADB 用法大全
增加一句 连接 网易mumu模拟器的方法 adb connect 127.0.0.1:7555 一份超全超详细的 ADB 用法大全 2016年08月28日 10:49:41 阅读数:35890 原文 ...
- (转)Springboot日志配置(超详细,推荐)
Spring Boot-日志配置(超详细) 更新日志: 20170810 更新通过 application.yml传递参数到 logback 中. Spring Boot-日志配置超详细 默认日志 L ...
随机推荐
- 实现 Emlog 最新评论列表不显示博主的评论回复
Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 实现 Emlog 最新评论列表不显示博主的评论回复 日期: ...
- Java跳动爱心代码
1.计算爱心曲线上的点的公式 计算爱心曲线上的点的公式通常基于参数方程.以下是两种常见的参数方程表示方法,用于绘制爱心曲线: 1.1基于 (x, y) 坐标的参数方程 x = a * (2 * cos ...
- java并发和排序的简单例子(Runnable+TreeSet)
很多时候并发需要考虑线程安全,但也有很多时候和线程安全毛关系都没有,因为并发最大的作用是并行,线程安全仅仅是并发的一个子话题. 例如常常会用于并发运算,并发i/o. 下文是一个练习笔记. 运行环境:w ...
- Kubernetes(四)Pod详解
Pod详解 本章主要介绍Pod资源的各种配置(yaml文件)和原理 1. Pod介绍 如上图所示,每个Pod中都可以包含一个或多个Container,这些Containers 可以分为2类: 用户程序 ...
- Bike Sharing Analysis(二)- 假设检验方法
假设检验 假设检验是推论统计学(inferential statistics)的一个分支,也就是对一个较小的.有代表性的数据组(例如样本集合)进行分析与评估,并依此推断出一个大型的数据组(例如人口)的 ...
- Android 7 默认声音/大小修改
背景 客户机器默认的开机声音一直很大:客户觉得无法接受,需要改小点. 基于Android 7的代码 前言 一般主要通过系统层来进行修改. 在系统关于音频的有关代码中,定义了两个数组: 注意,这些代码根 ...
- 2-SET详解
前置知识 SET问题的标准定义:在计算机科学中,布尔可满足性问题(有时称为命题可满足性问题,缩写为SATISFIABILITY或SAT)是确定是否存在满足给定布尔公式的解释的问题.(全是废话) 说人话 ...
- Unity中自定义应用程序打开Assets目录下指定类型的文件
在Unity使用VS2017打开unityShader文件时总提示错误: 我也一直没找啥原因,shader文件直接使用VSCode打开,当然其他类型的文件也可这样处理用相应的exe打开,如:pdf,t ...
- CF1864F 题解
写了一小时结果被卡常了(笑. 考虑新加入一个数什么时候会产生贡献,或者什么时候不会产生贡献. 发现当一个数的位置与他前一次出现时的位置所构成的区间内假若有一个比它小的数那么就不得不对这个数新进行一次操 ...
- 深耕分析型数据库领域,火山引擎ByteHouse入围《2024爱分析数据库厂商全景报告》
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群. 近日,爱分析发布<2024爱分析·数据库厂商全景报告>,报告中爱分析将数据市场从上至下划分为数据库服 ...