RabbitMQ:
RabbitMQ:六种模式:
- 简单模式
- work模式
- Publish/Subscribe发布与订阅模式
- Routing路由模式
- Topics主题模式
- RPC远程调用模式(远程调用,不能够算MQ,暂不介绍)
1.简单模式:
- P:生产者,也就是要发送消息的程序
- C:消费者,消息的接收者,会一直等待消息到来
- queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。
案例:
//Producer
package com.xzk.mq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private static String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 主机地址:默认localhost
connectionFactory.setHost("xxx.xxx.xxx.xxx");
// 连接端口:默认5672
connectionFactory.setPort(5672);
// 虚拟主机名:默认为 /
connectionFactory.setVirtualHost("/zxk");
// 连接用户名:默认为guest
connectionFactory.setUsername("xxxxxx");
// 连接密码:默认为guest
connectionFactory.setPassword("xxxxxx");
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* param1: 队列名称
* param2: 是否定义持久化队列
* param3: 是否独占本次连接, 只能由一个consumer消费队列
* param4: 是否在不使用的时候自动删除队列, 当没有consumer自动删除队列
* param5: 队列其它参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
String message = "hello: this is rabbitmq's producer";
// 发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println("消息已发送-----");
//释放资源
channel.close();
connection.close();
}
}
//Consumer
package com.xzk.mq.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer {
private static String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 主机地址:默认localhost
connectionFactory.setHost("xxx.xxx.xxx.xxx");
// 连接端口:默认5672
connectionFactory.setPort(5672);
// 虚拟主机名:默认为 /
connectionFactory.setVirtualHost("/zxk");
// 连接用户名:默认为guest
connectionFactory.setUsername("xxxxxx");
// 连接密码:默认为guest
connectionFactory.setPassword("xxxxxx");
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
//接收消息
com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
2.Work-Queues工作队列模式
work Queues与简单模式相比,多了一个或一些消费者,多个消费端共同消费同一个队列中的消息。
应用场景:对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
在一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系
案例:
//Producer, 这里把上面的连接代码封装了起来ConnectionUtils
package com.xzk.mq.workqueues;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private static String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
/**
* param1: 队列名称
* param2: 是否定义持久化队列
* param3: 是否独占本次连接, 只能由一个consumer消费队列
* param4: 是否在不使用的时候自动删除队列, 当没有consumer自动删除队列
* param5: 队列其它参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
for(int i = 0; i < 30; i++){
String message = "hello: this is rabbitmq's producer, queue_mode:work_queue == " + i;
// 发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
}
System.out.println("消息已发送-----");
//释放资源
channel.close();
connection.close();
}
}
//Consumer1
package com.xzk.mq.workqueues;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer1 {
private static String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
//接收消息
com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者1 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
//Consumer2
package com.xzk.mq.workqueues;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer2 {
private static String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
//接收消息
com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者2 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
3.订阅模式
前面两个案例中,只有三个角色:
- P:生产者,也就是要发送消息的程序
- C:消费者,消息的接收者,会一直等待消息到来
- queue:消息队列,图中红色部分
而在订阅者模型中,多了一个exchange角色,而且过程略有变化
- P:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发送给x(交换机)
- C:消费者,消息的接收者,会一直等待消息到来
- queue:消息队列,接收消息 、缓存消息
- Exchange:交换机,图中的X。一方面,接受生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见以下三种类型:
- Fanout:广播,将消息交给所有绑定到交换机的队列
- Direct:定向,把消息交给符合指定routing key 的队列
- Topic:通配符,把消息交给符合routing pattern(路由模式)的队列
Exchange只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会直接消失!
3.1Publish/Subscribe发布与订阅模式(Fanout)
发布订阅模式:
- 每个消费者监听自己的队列
- 生产者将消息发送给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息
案例:
//Producer
package com.xzk.mq.pubsub;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private static String FANOUT_EXCHANGE = "fanout_exchange";
private static String FANOUT_QUEUE_1 = "fanout_queue_1";
private static String FANOUT_QUEUE_2 = "fanout_queue_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明交换机
/**
* param1: 交换机名称
* param2: 交换机类型:fanout,direct,topic,headers
*/
channel.exchangeDeclare(FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT);
// 声明(创建)队列
/**
* param1: 队列名称
* param2: 是否定义持久化队列
* param3: 是否独占本次连接, 只能由一个consumer消费队列
* param4: 是否在不使用的时候自动删除队列, 当没有consumer自动删除队列
* param5: 队列其它参数
*/
channel.queueDeclare(FANOUT_QUEUE_1, true, false, false, null);
channel.queueDeclare(FANOUT_QUEUE_2, true, false, false, null);
// 队列绑定交换机
channel.queueBind(FANOUT_QUEUE_1, FANOUT_EXCHANGE, "");
channel.queueBind(FANOUT_QUEUE_2, FANOUT_EXCHANGE, "");
for(int i = 0; i < 30; i++){
String message = "hello: this is rabbitmq's producer, queue_mode:publish/subscribe,fanout == " + i;
// 发送消息
channel.basicPublish(FANOUT_EXCHANGE, "", null, message.getBytes());
}
System.out.println("消息已发送-----");
//释放资源
channel.close();
connection.close();
}
}
//Consumer1
package com.xzk.mq.pubsub;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer1 {
private static String FANOUT_EXCHANGE = "fanout_exchange";
private static String FANOUT_QUEUE_1 = "fanout_queue_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
channel.queueDeclare(FANOUT_QUEUE_1, true, false, false, null);
// 绑定交换机
channel.queueBind(FANOUT_QUEUE_1, FANOUT_EXCHANGE, "");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者1 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(FANOUT_QUEUE_1, true, consumer);
}
}
//Consumer2
package com.xzk.mq.pubsub;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer2 {
private static String FANOUT_EXCHANGE = "fanout_exchange";
private static String FANOUT_QUEUE_2 = "fanout_queue_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
channel.queueDeclare(FANOUT_QUEUE_2, true, false, false, null);
// 绑定交换机
channel.queueBind(FANOUT_QUEUE_2, FANOUT_EXCHANGE, "");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者2 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(FANOUT_QUEUE_2, true, consumer);
}
}
3.2Routing路由模式(Direct)
特点:
- 队列与交换机的绑定,不能是任意绑定,而是要指定一个Routingkey(路由key)
- 消息的发送方在向Exchange发送消息时,也必须指定消息的RoutingKey
- Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的RoutingKey与消息的Routing Key完全一致,才会接收到消息
图解:
- P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。
- X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列
- C1:消费者,其所在队列指定了需要routing key 为 error 的消息
- C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息
案例:
//Producer
package com.xzk.mq.pubsub.direct;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private static String DIRECT_EXCHANGE = "direct_exchange";
private static String DIRECT_QUEUE_INSERT = "direct_queue_1";
private static String DIRECT_QUEUE_UPDATE = "direct_queue_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明交换机
/**
* param1: 交换机名称
* param2: 交换机类型:fanout,direct,topic,headers
*/
channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
// 声明(创建)队列
/**
* param1: 队列名称
* param2: 是否定义持久化队列
* param3: 是否独占本次连接, 只能由一个consumer消费队列
* param4: 是否在不使用的时候自动删除队列, 当没有consumer自动删除队列
* param5: 队列其它参数
*/
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");
// 新增消息
for(int i = 0; i < 30; i++){
String message = "新增消息, 路由 模式, routingkey insert :" + i;
// 发送消息
channel.basicPublish(DIRECT_EXCHANGE, "insert", null, message.getBytes());
}
// 修改消息
for(int i = 0; i < 30; i++){
String message = "修改消息, 路由 模式, routingkey update :" + i;
// 发送消息
channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());
}
System.out.println("消息已发送-----");
//释放资源
channel.close();
connection.close();
}
}
//Consumer1
package com.xzk.mq.pubsub.direct;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer1 {
private static String DIRECT_EXCHANGE = "direct_exchange";
private static String DIRECT_QUEUE_INSERT = "direct_queue_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null);
// 绑定交换机
channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者1 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(DIRECT_QUEUE_INSERT, true, consumer);
}
}
//Consumer2
package com.xzk.mq.pubsub.direct;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer2 {
private static String DIRECT_EXCHANGE = "direct_exchange";
private static String DIRECT_QUEUE_UPDATE = "direct_queue_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明(创建)队列
channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null);
// 绑定交换机
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者2 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(DIRECT_QUEUE_UPDATE, true, consumer);
}
}
3.3Topics通配符模式
Topic类型与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候使用通配符
RoutingKey一般都是有一个或多个单词组成,多个单词之间以“.”分割,例如:item.insert
通配符规则:
#:匹配一个或多个词
*:匹配不多不少恰好一个词
举例:
item.#:能够匹配item.insert.abc或者item.insert
item.*:只能匹配item.insert
图解:
-
红色Queue:绑定的是 usa.# ,因此凡是以 usa. 开头的 routing key 都会被匹配到
-
黄色Queue:绑定的是 #.news ,因此凡是以 .news 结尾的 routing key 都会被匹配
案例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Iz93qGH-1604656634904)(C:\Users\ccc-j\AppData\Roaming\Typora\typora-user-images\image-20201106162055569.png)]
//Producer
package com.xzk.mq.pubsub.topics;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private static String TOPIC_EXCHANGE = "topic_exchange";
private static String TOPIC_QUEUE_ALL = "topic_queue_all";
private static String TOPIC_QUEUE_UPDATE_INSERT = "topic_queue_update_insert";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明交换机
/**
* param1: 交换机名称
* param2: 交换机类型:fanout,direct,topic,headers
*/
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
// 新增消息
String message1 = "新增消息, topic 模式, routingkey insert";
// 发送消息
channel.basicPublish(TOPIC_EXCHANGE, "item.insert", null, message1.getBytes());
// 修改消息
String message2 = "新增消息, topic 模式, routingkey update";
// 发送消息
channel.basicPublish(TOPIC_EXCHANGE, "item.update", null, message2.getBytes());
// 删除消息
String message3 = "新增消息, topic 模式, routingkey delete";
// 发送消息
channel.basicPublish(TOPIC_EXCHANGE, "item.delete", null, message2.getBytes());
System.out.println("消息已发送-----");
//释放资源
channel.close();
connection.close();
}
}
//Consumer1
package com.xzk.mq.pubsub.topics;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer1 {
private static String TOPIC_EXCHANGE = "topic_exchange";
private static String TOPIC_QUEUE_ALL = "topic_queue_all";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
// 声明(创建)队列
channel.queueDeclare(TOPIC_QUEUE_ALL, true, false, false, null);
// 绑定交换机
channel.queueBind(TOPIC_QUEUE_ALL, TOPIC_EXCHANGE, "item.*");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者1 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(TOPIC_QUEUE_ALL, true, consumer);
}
}
//Consumer2
package com.xzk.mq.pubsub.topics;
import com.rabbitmq.client.*;
import com.xzk.mq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer2 {
private static String TOPIC_EXCHANGE = "topic_exchange";
private static String TOPIC_QUEUE_ALL = "topic_queue_all";
private static String TOPIC_QUEUE_UPDATE_INSERT = "topic_queue_update_insert";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建通道(channel)
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare(TOPIC_QUEUE_UPDATE_INSERT, BuiltinExchangeType.TOPIC);
// 声明(创建)队列
channel.queueDeclare(TOPIC_QUEUE_UPDATE_INSERT, true, false, false, null);
// 绑定交换机
channel.queueBind(TOPIC_QUEUE_UPDATE_INSERT, TOPIC_EXCHANGE, "item.update");
//接收消息
Consumer consumer = new DefaultConsumer(channel){
/**
* 接收到消息执行的回调
* @param consumerTag 消费者标签、在channel.basicConsumer时可以指定
* @param envelope 消息内容
* @param properties 消息配置属性
* @param body 消息体
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
// 收到的消息信息
System.out.println("消费者2 - 接收到的消息信息是:" + new String(body, "utf-8"));
}
};
channel.basicConsume(TOPIC_QUEUE_UPDATE_INSERT, true, consumer);
}
}
模式总结
- 简单模式
- 一个生产者、一个消费者,不需要设置交换机(使用默认的交换机)
- 工作队列模式
- 一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认的交换机)
- 发布订阅模式(Publish/Subscribe)
- 需要设置类型为fanout的交换机,交换机和队列绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列
- 路由模式(Routing)
- 需要设置类型为direct的交换机,交换机和队列绑定,并且指定routingkey,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
- 通配符模式(Topic)
- 需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的消息队列