RabbitMQ(基于AMQP)
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库
- MQ是消息通信的模型:实现MQ的两种主流方式:AMQP(连接协议)/JMS(网络交互).
- AMQP(跨语言):通过规定协议统一数据交互格式
- JMS(必须java):定义统一接口,对消息进行统一处理
- RabbitMQ只能从队列中接收消息
RabbitMQ六种工作模式:
-
simple简单模式: 单生产单消费;
-
work模式:在同一个队列中可以有多个消费者,消费者之间对消息的接收是竞争的,一个消息只能被一个消费者接收,多个消费者不会接收到同一个消息;
-
Publish/Subscribe发布与订阅模式:一个消息可以被多个消费者接收,交换机类型为:fanout广播模式,生产者将消息发送到交换器,然后交换器绑定到多个队列,监听该队列的所有消费者消费消息
-
Routing路由模式:队列与交换机绑定,需要指定一个RoutingKey(路由key),消息的发送者在向Exchange(交换机)发送消息时,必须指定消息的RoutingKey,Exchange不再把消息交给每一个绑定的队列中,而是根据消息指定的RoutingKey进行判断,只有队列的RoutingKey与消息的RoutingKey完全匹配,才能接收到消息;
-
Topics通配符模式(常用):类似于正则表达式匹配的一种模式。主要使用#、*进行匹配
-
RabbitMQ使用步骤(简单模式)__>后面将相同的代码(创建连接)抽取成了一个工具类_>操作步骤在代码体现不想写测试可以copy
- 生产者发送消息到RabbitMQ消息队列,消费者从队列中获取消息,可以使用RabbitMQ的简单模式(simple)
- 生产者发送消息步骤:
- 创建连接工厂(设置RabbitMQ的连接参数);
- 创建连接;
- 创建频道;
- 声明队列;
- 发送消息;
- 关闭资源;
/**
* 简单模式发送消息
*/
public class Producer {
static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//1- 创建连接工厂(设置RabbitMQ的连接参数);
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(8888);
connectionFactory.setVirtualHost("/zhupeiliang");
connectionFactory.setUsername("zhupeiliang");
connectionFactory.setPassword("zhupeiliang");
//2- 创建连接;
Connection connection = connectionFactory.newConnection();
//3- 创建频道;
Channel channel = connection.createChannel();
//4- 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//5- 发送消息;
String message = "你好,rabbitMQ!!!";
/*
* 参数1:交换机名称,如果没有则指定空字符串(表示使用默认的交换机)
* 参数2:路由key,简单模式中可以使用队列名称
* 参数3:消息其它属性,没有指定null
* 参数4:消息内容
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
//6- 关闭资源;
channel.close();
connection.close();
}
}
- 消费者消费消息步骤:(从RabbitMQ队列接收消息__>与生产者发送消息是的队列一致)
- 创建连接工厂;
- 创建连接;
- 创建频道;
- 声明队列;
- 创建消费者(接收消息并处理消息);
- 监听队列
/**
* 简单模式,:消费者消费消息
*/
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println(envelope.getRoutingKey());
System.out.println(envelope.getExchange());
System.out.println(envelope.getDeliveryTag());
System.out.println(new String(body, "urf-8"));
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.QUEUE_NAME, true, defaultConsumer);
}
}
RabbitMQ(work工作队列模式)
- 生产者:
/**
*work模式发送消息
*/
public class Producer {
static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//1- 创建连接工厂(设置RabbitMQ的连接参数);
//2- 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3- 创建频道;
Channel channel = connection.createChannel();
//4- 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
for (int i = 1; i <= 30; i++) {
//5- 发送消息;
//定义消息体
String message = "你好,rabbitMQ!!!---work摩丝" + i;
/
* 参数1:交换机名称,如果没有则指定空字符串(表示使用默认的交换机)
* 参数2:路由key,简单模式中可以使用队列名称
* 参数3:消息其它属性,没有指定null
* 参数4:消息内容
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(message);
}
//6- 关闭资源;
channel.close();
connection.close();
}
}
- 消费者1:
/**
* work模式,:消费者消费消息
*/
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);
//设置每次可以预取多少个消息
channel.basicQos(1);
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
try {
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
System.out.println("消费者1接收到消息内容:" + new String(body, "UTF-8"));
Thread.sleep(1000);
//确认消息是否被消费,参数1:消息id,参数2:false表示只有当前这条消息被处理了
channel.basicAck(envelope.getDeliveryTag(), false);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.QUEUE_NAME, true, defaultConsumer);
}
}
- 消费者2: 跟消费者1代码相同,只是消费同一个队列的消息
RabbitMQ(发布与订阅模式)
- 一个消息发送之后可以让多个或者所有消费者接收到消息,消费者只能监听一个队列
- 多了一个角色__>Exchange交换机,接收生产者发送的消息并决定如何投递消息到其绑定的队列,消息的投递取决于交换机的类型;
- 交换机类型:
- 广播(fanout):将消息交给所有绑定交换机的队列
- 定向(direct):把消息交给 符合指定routingKey的队列
- 通配符(topic):把消息交给符合routingPattern(路由模式)的队列
- 广播模式示例:
- 生产者:
/**
* 发布与订阅模式发送消息
*/
public class Producer {
//交换机名称_广播类型
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 void main(String[] args) throws IOException, TimeoutException {
//1- 创建连接工厂(设置RabbitMQ的连接参数);
Connection connection = ConnectionUtil.getConnection();
//2- 创建频道;
Channel channel = connection.createChannel();
//3-声明交换机,参数1:交换机名称,参数2:交换机类型-广播类型(&&-->fanout,direct,topic)
channel.exchangeDeclare(FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT);
//4- 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(FANOUT_QUEUE_1, true, false, false, null);
channel.queueDeclare(FANOUT_QUEUE_2, true, false, false, null);
//4.1- 队列绑定到交换机,参数1:队列名称;参数2:交换机名称;参数3:路由key,没有设置空
channel.queueBind(FANOUT_QUEUE_1, FANOUT_EXCHANGE, "");
channel.queueBind(FANOUT_QUEUE_2, FANOUT_EXCHANGE, "");
for (int i = 1; i <= 10; i++) {
//5- 发送消息;
String message = "你好,rabbitMQ!!!--发布与订阅摩丝------" + i;
/*
* 参数1:交换机名称,如果没有则指定空字符串(表示使用默认的交换机)
* 参数2:路由key,简单模式中可以使用队列名称
* 参数3:消息其它属性,没有指定null
* 参数4:消息内容
*/
channel.basicPublish(FANOUT_EXCHANGE, "", null, message.getBytes());
channel.basicPublish(FANOUT_EXCHANGE, "", null, message.getBytes());
System.out.println(message);
}
//6- 关闭资源;
channel.close();
connection.close();
}
}
- 消费者1:
/**
* 发布与订阅模式,:消费者消费消息
*/
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//3.1 - 声明交换机
channel.exchangeDeclare(Producer.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT);
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.FANOUT_QUEUE_1, true, false, false, null);
// channel.queueDeclare(Producer.FANOUT_QUEUE_2, true, false, false, null);
//4.1 - 队列绑定到交换机上;参数1:队列名称;参数2:交换机名称;参数3:路由key
channel.queueBind(Producer.FANOUT_QUEUE_1, Producer.FANOUT_EXCHANGE, "");
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
// System.out.println(new String(body));
System.out.println("消费者1---消费消息::" + new String(body, "UTF-8"));
// System.out.println("?");
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.FANOUT_QUEUE_1, true, defaultConsumer);
}
}
- 消费者2:与消费者1一样,更换监听 队列即可
RabbitMQ(Routing路由模式)
- 生产者:发送两条消息(路由key分别为: insert , update__[路由key随意指定,消费者指定的路由key必须跟生产者一致])
/**
* RoutingKey路由模式发送消息
*/
public class Producer {
//交换机名称_路由类型
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 void main(String[] args) throws IOException, TimeoutException {
//1- 创建连接工厂(设置RabbitMQ的连接参数);
Connection connection = ConnectionUtil.getConnection();
//2- 创建频道;
Channel channel = connection.createChannel();
//3-声明交换机,参数1:交换机名称,参数2:交换机类型-路由类型(&&-->fanout,direct,topic)
channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
//4- 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null);
channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null);
//4.1- 队列绑定到交换机,参数1:队列名称;参数2:交换机名称;参数3:路由key,没有设置空
channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert");
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update");
//5- 发送消息;
String message = "你好,rabbitMQ!!!--路由摩丝----RoutingKey为-->insert";
/*
* 参数1:交换机名称,如果没有则指定空字符串(表示使用默认的交换机)
* 参数2:路由key,简单模式中可以使用队列名称
* 参数3:消息其它属性,没有指定null
* 参数4:消息内容
*/
channel.basicPublish(DIRECT_EXCHANGE, "insert", null, message.getBytes());
System.out.println(message);
//5- 发送消息;
message = "你好,rabbitMQ!!!--路由摩丝----RoutingKey为-->update";
/*
* 参数1:交换机名称,如果没有则指定空字符串(表示使用默认的交换机)
* 参数2:路由key,简单模式中可以使用队列名称
* 参数3:消息其它属性,没有指定null
* 参数4:消息内容
*/
channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());
System.out.println(message);
//6- 关闭资源;
channel.close();
connection.close();
}
}
- 消费者:创建两个消费者,监听的队列分别绑定的路由key为: insert , updatea
/**
* RoutingKey路由模式,:消费者消费消息
*/
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//3.1 - 声明交换机,模式为路由模式
channel.exchangeDeclare(Producer.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.DIRECT_QUEUE_INSERT, true, false, false, null);
//4.1 - 队列绑定到交换机上;参数1:队列名称;参数2:交换机名称;参数3:路由key
channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHANGE, "insert");
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
System.out.println("消费者1---消费消息::" + new String(body, "UTF-8"));
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.DIRECT_QUEUE_INSERT, true, defaultConsumer);
}
}
- 消费者同上,切换消费者监听的消息队列
- *__>RoutingKey路由模式要求队列绑定到交换机的时候指定路由key,生产者发送消息的时候需要携带路由key,只有消息的路由key与队列的路由key相同时,才能让该队列接收到消息;
RabbitMQ(topic通配符模式):
- 生产者:发送消息包含有:dg.insert,dg.update,dg.delete的三种路由key的消息
/**
* topic通配符模式,:消费者消费消息
*/
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//3.1 - 声明交换机,模式为路由模式
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.TOPIC_EXCHANGE, true, false, false, null);
//4.1 - 队列绑定到交换机上;参数1:队列名称;参数2:交换机名称;参数3:路由key
channel.queueBind(Producer.TOPIC_QUEUE_1,Producer.TOPIC_EXCHANGE, "dg.update");
channel.queueBind(Producer.TOPIC_QUEUE_1,Producer.TOPIC_EXCHANGE, "dg.delete");
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
System.out.println("消费者1---消费消息::" + new String(body, "UTF-8"));
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.TOPIC_QUEUE_1, true, defaultConsumer);
}
}
- 消费者1:监听的队列绑定到交换的的路由key为:dg.update , dg.delete
/**
* topic通配符模式,消费者消费消息
*/
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//3.1 - 声明交换机,模式为路由模式
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.TOPIC_EXCHANGE, true, false, false, null);
//4.1 - 队列绑定到交换机上;参数1:队列名称;参数2:交换机名称;参数3:路由key
channel.queueBind(Producer.TOPIC_QUEUE_1,Producer.TOPIC_EXCHANGE, "dg.update");
channel.queueBind(Producer.TOPIC_QUEUE_1,Producer.TOPIC_EXCHANGE, "dg.delete");
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
System.out.println("消费者1---消费消息::" + new String(body, "UTF-8"));
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.TOPIC_QUEUE_1, true, defaultConsumer);
}
}
- 消费者2:监听的队列绑定到交换机的路由key为: dg.*
/**
* topic通配符模式,:消费者消费消息
*/
public class Consumer2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1 - 创建连接工厂;
//2 - 创建连接;
Connection connection = ConnectionUtil.getConnection();
//3 - 创建频道;
Channel channel = connection.createChannel();
//3.1 - 声明交换机,模式为路由模式
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
//4 - 声明队列;
/*
*参数1:队列名称
*参数2:定义持久化到服务器上,
*参数3:是否独占本连接,
*参数4:是否在不使用的时候将队列自动删除,
*参数5:其他参数
*/
channel.queueDeclare(Producer.TOPIC_EXCHANGE, true, false, false, null);
//4.1 - 队列绑定到交换机上;参数1:队列名称;参数2:交换机名称;参数3:路由key
channel.queueBind(Producer.TOPIC_QUEUE_2, Producer.TOPIC_EXCHANGE, "dg.*");
//5 - 创建消费者(接收消息并处理消息);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//输出信息:__>/路由key/交换机/消息id/接收到的消息
System.out.println("路由key:" + envelope.getRoutingKey());
System.out.println("交换机:" + envelope.getExchange());
System.out.println("消息id:" + envelope.getDeliveryTag());
System.out.println("消费者1---消费消息::" + new String(body, "UTF-8"));
}
};
//6 -监听队列
/*
参数1:队列名称
参数2:是否自动确认,设置为true,表示消息接收到自动向MQ回复接收到了,MQ则会将消息从队列中自动删除,反之需要手动删除
参数3:消费者
*/
channel.basicConsume(Producer.TOPIC_QUEUE_2, true, defaultConsumer);
}
}
使用RabbitMQ总结:两种模式:
- 不使用Exchange交换机:(使用默认交换机)
1.simple简单模式:一个生产者生产 一个消息到一个队列被一个消费者接收消费
2.work工作模式:生产者发送消息到队列,可以被多个消费者监听该队列,但是一个消息只能被一个消费者消费; - 使用Exchange交换机:
- 订阅模式(交换机:fanout广播,direct定性,topic通配符)
1.发布与订阅模式:使用fanout广播类型的交换机,可以将一个消息发送到所有绑定了该交换机的队列;
2.路由模式:使用了direct定向类型的交换机,消息会携带路由key,交换机根据消息的路由key与队列的路由key进行匹配,匹配之后该队列接收消息,消费;
3.通配符模式:使用了topic通配符模式类型的交换机,消息会携带路由key,交换机根据消息的路由key与队列的路由key(,#)进行匹配,匹配之后该队列接收消息,消费;
" * ">匹配一个词 , 例如:dg.>只能匹配 dg.xxx
" # ">匹配一个词或者多个词, 例如:dg.#>能够匹配dg.xxx.xxx , dg.xxx
- 订阅模式(交换机:fanout广播,direct定性,topic通配符)
RabbitMQ与SpringBoot整合
1.导入坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
2.生产者配置spring.yml配置文件.rabbitMQ的连接参数
spring:
rabbitmq:
host: localhost
port: 5672
virtual-host: /dg
username: dg
password: dg
3.创建消息生产者,topic通配符模式
@Configuration
public class RabbitMQConfig {
//交换机名称
public static final String DG_TOPIC_EXCHANGE = "dg_topic_exchange";
//队列名称
public static final String DG_QUEUE = "dg_queue";
//声明交换机
@Bean("dgTopicExchange")
public Exchange topicExchange() {
return ExchangeBuilder.topicExchange(DG_TOPIC_EXCHANGE).durable(true).build();
}
//声明队列
@Bean("dgQueue")
public Queue dgQueue() {
return QueueBuilder.durable(DG_QUEUE).build();
}
//将队列绑定到交换机
@Bean
public Binding bindingQueueExchange(@Qualifier("dgTopicExchange") Exchange exchange,
@Qualifier("dgQueue") Queue queue) {
return BindingBuilder.bind(queue).to(exchange).with("dg.#").noargs();
}
}
4.创建消费者:topic通配符模式
消费者监听的队列名称必须跟消息生产者发送消息的队列名称要匹配;
- SpringBoot提供了对于AMQP整合,可以使用RabbitMQTemplate发送消息,可以使用@RabbitListener注解接收消息;
@Component
public class RabbitMQConsumer {
/**
* 接收队列消息
* @param message 消息内容
* @RabbitListener(queues = "dgQueue")参数可以监听多个队列 例如:
* @RabbitListener(queues = {"q1","q2"})
*/
@RabbitListener(queues = "dgQueue")
public void rabbitMQListener(String message) {
System.out.println("消费者接收到的消息为:" + message);
}
}
5.消息生产者工程中编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRabbitmqProducerApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void mqContextLoads() {
rabbitTemplate.convertAndSend(RabbitMQConfig.DG_TOPIC_EXCHANGES, "inserts", "路由key为:dg.inserts");
rabbitTemplate.convertAndSend(RabbitMQConfig.DG_TOPIC_EXCHANGES, "deletes", "路由key为:dg.deletes");
rabbitTemplate.convertAndSend(RabbitMQConfig.DG_TOPIC_EXCHANGES, "updates", "路由key为:dg.updates");
rabbitTemplate.convertAndSend(RabbitMQConfig.DG_TOPIC_EXCHANGES, "selects", "路由key为:dg.selects");
}
}
如有不对的地方,请各路大神指正 ~