简单的说就是队列里面的消息会被多个消费者同时接受到,消费者接收到的信息一致
发布订阅模型适合于做模块之间的异步通信
场景:
// 生产者
public class Producer {
// 声明交换机的名字
private static final String EXCHANGE_NAME = "exchange_publish_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明交换机
/**
* param1:exchange,交换机的名称
* param2:type,交换机的类型,发布订阅模式只能是 fanout
*/
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
// 发送消息到交换机
for (int i = 0; i < 100; i++) {
channel.basicPublish(EXCHANGE_NAME, "", null, ("发布订阅模型的第 " + i + " 条消息").getBytes());
}
// 关闭资源
channel.close();
connection.close();
}
}
// 消费者1
public class Consumer {
// 声明队列的名字
private static final String QUEUE_NAME = "queue_publish_1";
// 声明交换机的名字
private static final String EXCHANGE_NAME = "exchange_publish_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
// 将队列绑定到交换机
/**
* param1:destination,目的地,队列的名字
* param2:source,资源,交换机的名字
* param3:routingKey,路由键(目前没有用到routingKey,填 "" 即可)
*/
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
// 声明消费者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("队列1接收到的消息是:" + new String(body));
}
};
// 绑定消费者,自动应答
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
}
}
// 消费者2
public class Consumer2 {
// 声明队列的名字
private static final String QUEUE_NAME = "queue_publish_2";
// 声明交换机的名字
private static final String EXCHANGE_NAME = "exchange_publish_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
// 将队列绑定到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
// 声明消费者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("队列2接收到的消息是:" + new String(body));
}
};
// 绑定消费者,自动应答
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
}
}
先启动2个消费者,再启动生产者
运行结果
可以看出来消费者1和消费者2接收到的消息是一模一样的
/**
* @param exchange the name of the exchange
* @param type the exchange type
* @param durable true if we are declaring a durable exchange (the exchange will survive a server restart)
* @param autoDelete true if the server should delete the exchange when it is no longer in use
* @param internal true if the exchange is internal, i.e. can't be directly
* published to by a client.
* @param arguments other properties (construction arguments) for the exchange
*/
Exchange.DeclareOk exchangeDeclare(String exchange,
String type,
boolean durable,
boolean autoDelete,
boolean internal,
Map<String, Object> arguments) throws IOException;
Exchange.DeclareOk exchangeDeclare(String exchange,
BuiltinExchangeType type,
boolean durable,
boolean autoDelete,
boolean internal,
Map<String, Object> arguments) throws IOException;
/**
* @param queue the name of the queue
* @param exchange the name of the exchange
* @param routingKey the routing key to use for the binding
* @param arguments other properties (binding parameters)
*/
Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments) throws IOException;
RabbitMQ通讯模型系列
RabbitMQ从零开始学(二)—通信模型之HelloWorld型—channel方法参数详解
RabbitMQ从零开始学(三)—通信模型之Work型—channel.basicQos()
RabbitMQ从零开始学(五)—通信模型之路由模型(direct)
RabbitMQ从零开始学(六)—通信模型之topic模型—通信模型总结