Pub-Sub模式
在订阅模式中,多了一个Exchange角色,而且过程略有变化
P:生产者,将消息发给交换机
C:消费者,等待消息到来
Queue:消息队列,缓存接收消息
Exchange:一方面接收生产者发送的消息,另一方面,知道如何处理消息,例如传递给某个特别队列
递交给所有队列,或是将消息丢弃,到底如何操作,取决于Exchange的类型
常见类型有:
Fanout:广播,将消息交给所有绑定到交换机的队列
Direct:定向,把消息交给复合物指定routingkey的队列
Topic:通配符,把消息交给符合routing pattern(路由模式)的队列
Exchange:只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!
生产者代码
package com.pubSub;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
/**
* Publish/Subscribe pubSubProductor
* @date 2023-02-19 21:11
*/
public class PubSubProductor {
private final static String QUEUE_NAME_ONE = "pub_sub_01";
private final static String QUEUE_NAME_TWO = "pub_sub_02";
private final static String EXCHANGE_NAME = "test_fanout";
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置一些参数
factory.setHost("192.168.1.25"); // ip默认值localhost
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("123456");
factory.setVirtualHost("/itcast");
Connection connection = null;
Channel channel = null;
try {
// 3、获取对应的连接
connection = factory.newConnection();
// 4、创建channel
channel = connection.createChannel();
// 5、创建交换机
/**
* void exchangeDeclareNoWait(
* String exchange,交换机名称
* BuiltinExchangeType type,交换机类型 ## DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers");
* boolean durable,是否持久化
* boolean autoDelete,是否自动删除
* boolean internal,是否内部,一般都是false
* Map<String, Object> arguments,参数列表
* ) throws IOException;
*/
channel.exchangeDeclareNoWait(EXCHANGE_NAME, BuiltinExchangeType.FANOUT, false, false, false, null);
// 6、创建队列
channel.queueDeclare(QUEUE_NAME_ONE, false, false, false, null);
channel.queueDeclare(QUEUE_NAME_TWO, false, false, false, null);
// 7、绑定队列和交换机
/**
* String queue, 队列名称
* String exchange, 交换机名称
* String routingKey, 路由键绑定规则
* 如果交换机类型为 fanout ,设置为空字符串,因为消息需要推送给每个消费者
* Map<String, Object> arguments, 参数 可以写null
*/
channel.queueBind(QUEUE_NAME_ONE, EXCHANGE_NAME, "", null);
channel.queueBind(QUEUE_NAME_TWO, EXCHANGE_NAME, "", null);
// 8、发送消息
for (int i = 1; i <= 100000; i++) {
String message = "hello word >>>>> " + i;
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 9、释放资源
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("消息发送完毕");
}
}
}
消费者代码(两个消费者,订阅的队列不同)
package com.pubSub;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* Publish/Subscribe PubSubConsumer01
* @date 2023-02-19 21:31
*/
public class PubSubConsumer01 {
private final static String QUEUE_NAME_ONE = "pub_sub_01";
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置一些参数
factory.setHost("192.168.1.25"); // ip默认值localhost
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("123456");
factory.setVirtualHost("/itcast");
// 3、获取对应的连接
Connection connection = null;
Channel channel = null;
try {
connection = factory.newConnection();
channel = connection.createChannel();
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String va1 = new String(delivery.getBody());
System.out.println("打印日志");
System.out.println(va1);
};
CancelCallback cancelCallback = (consumerTag) -> {
System.out.println("消息消费被中断");
};
/**
* 消费者消费消息
* 1.消费哪个队列
* 2.消费成功之后是否要自动应答 true 代表自动应答 false 手动应答
* 3.消费者未成功消费的回调
*/
channel.basicConsume(QUEUE_NAME_ONE, true, deliverCallback, cancelCallback);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("消费者不关闭资源");
}
}
}