概述:
在上一章节介绍的工作模式中,我们的消费会进行轮询发送给所有的消息消费者,每个消费者接受消息之和为全部消息。本章节介绍的订阅发布者模式则为:将消息传递给所有的消息消费者,每个消费者都能接受到全部的消息。并且在订阅发布章节我们将新引入一个新的概念,交换机(Exchange)概念。
一、pom.xml 依赖
只需要引入rabbitMq的依赖即可
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>RabbitMQ</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
</dependencies>
</project>
二、发布者(生产者)代码实现过程:
- 创建RabbitMQ连接对象Connection;
- 创建信道Channel;
- 使用Channel声明交换机信息(名称、类型),交换机类型有四种 direct,topic,headers 和fanout。本示例使用fanout;
- 声明所有的消息队列;
- 将消息队列与交换机进行绑定;
- 发送消息;
- 关闭信道和mq连接;
java代码实现如下:
package com.xiaohui.rabbitmq.publishSubscribe;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
//交换机名称
public static final String FANOUT_EXCHANGE = "fanout_exchange";
//队列1
public static final String FANOUT_QUEUE_1 = "fanout_queue_1";
//队列2
public static final String FANOUT_QUEUE_2 = "fanout_queue_2";
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//创建信道
Channel channel = connection.createChannel();
//声明交换机
/**
* 参数一:交换机名称
* 参数二:交换机类型:fanout \topic \direct
*/
channel.exchangeDeclare(Producer.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT);
/**
* 声明队列
* durabe:持久化的消息,mq重启后消息仍在。
* exclusive :独占的,一个消息队列独占一个连接
*/
channel.queueDeclare(Producer.FANOUT_QUEUE_1,true,false,false,null);
channel.queueDeclare(Producer.FANOUT_QUEUE_2,true,false,false,null);
//队列绑定交换机
channel.queueBind(Producer.FANOUT_QUEUE_1,Producer.FANOUT_EXCHANGE,"");
channel.queueBind(Producer.FANOUT_QUEUE_2,Producer.FANOUT_EXCHANGE,"");
for (int i = 1; i < 5; i++) {
String msg = "订阅发布模式小兔子来啦........"+i;
channel.basicPublish(Producer.FANOUT_EXCHANGE,"",null,msg.getBytes());
}
channel.close();
connection.close();
}
}
三、订阅者代码实现步骤
- 创建消费端链接
- 创建消费端渠道
- 声明交换机
- 声明消费队列
- 队列绑定到交换机
- 监听消息回调处理
- 消息监听开启
java代码实现如下:
package com.xiaohui.rabbitmq.publishSubscribe;
import com.rabbitmq.client.*;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Cunsumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建消费端链接
Connection connection = ConnectionUtils.getConnection();
//创建消费端渠道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(Producer.FANOUT_EXCHANGE,BuiltinExchangeType.FANOUT);
//声明消费队列
channel.queueDeclare(Producer.FANOUT_QUEUE_1, true,false,false,null);
//队列绑定到交换机
channel.queueBind(Producer.FANOUT_QUEUE_1,Producer.FANOUT_EXCHANGE,"");
//监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("==================订阅消费者1开始===================");
System.out.println("路由的key为:"+envelope.getRoutingKey());
System.out.println("交换机为:"+envelope.getExchange());
System.out.println("消息ID为:"+envelope.getDeliveryTag());
System.out.println("收到的消息为:"+new String(body,"UTF-8"));
System.out.println("===================订阅消费者1结束==================");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
/**
* 第二个参数表示是否 向mqserver自动回复收到
* 第三个参数表示消息回调
*/
channel.basicConsume(Producer.FANOUT_QUEUE_1,true,consumer);
}
}
订阅者2 代码实现:
package com.xiaohui.rabbitmq.publishSubscribe;
import com.rabbitmq.client.*;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Cunsumer2 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建消费端链接
Connection connection = ConnectionUtils.getConnection();
//创建消费端渠道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(Producer.FANOUT_EXCHANGE,BuiltinExchangeType.FANOUT);
//声明消费队列
channel.queueDeclare(Producer.FANOUT_QUEUE_2, true,false,false,null);
//队列绑定到交换机
channel.queueBind(Producer.FANOUT_QUEUE_2,Producer.FANOUT_EXCHANGE,"");
//监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("==================订阅消费者2开始===================");
System.out.println("路由的key为:"+envelope.getRoutingKey());
System.out.println("交换机为:"+envelope.getExchange());
System.out.println("消息ID为:"+envelope.getDeliveryTag());
System.out.println("收到的消息为:"+new String(body,"UTF-8"));
System.out.println("===================订阅消费者2结束==================");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
/**
* 第二个参数表示是否 向mqserver自动回复收到
* 第三个参数表示消息回调
*/
channel.basicConsume(Producer.FANOUT_QUEUE_2,true,consumer);
}
}
运行打印(两个控制台一样):
==================订阅消费者1开始===================
路由的key为:
交换机为:fanout_exchange
消息ID为:10
收到的消息为:订阅发布模式小兔子来啦........1
===================订阅消费者1结束==================
==================订阅消费者1开始===================
路由的key为:
交换机为:fanout_exchange
消息ID为:11
收到的消息为:订阅发布模式小兔子来啦........2
===================订阅消费者1结束==================
==================订阅消费者1开始===================
路由的key为:
交换机为:fanout_exchange
消息ID为:12
收到的消息为:订阅发布模式小兔子来啦........3
===================订阅消费者1结束==================
==================订阅消费者1开始===================
路由的key为:
交换机为:fanout_exchange
消息ID为:13
收到的消息为:订阅发布模式小兔子来啦........4
===================订阅消费者1结束==================