Rabbitmq
什么是rabbitmq?
一款基于AMQP(高级消息队列协议)用于软件之间通信的中间件,AMQP是一种二进制协议,它定义了一组规则和标准,以确保消息可以在不同的应用程序和平台之间传递并解释,AMQP协议包含四个核心组件:消息、交换机、队列、绑定
消息队列的应用场景
- 应用解耦
- 返回响应速度提高
- 流量削峰
Rabbitmq四大核心
- 生产者
- 消费者
- 队列
- 交换机
消息队列的特点
- 易用性
- 扩展性
- 高可用
消息队列的缺点
- 降低系统的可用性:引入外部依赖越多,越可能出问题
- 系统复杂度提高
- 一致性问题
组成部分
- Broker:接受和分发消息的应用,RabbitMQ Server就是Message Broker
- Virtual host:虚拟主机,一个Borker中可以有对个虚拟主机,不同的虚拟主机中的exchange和queue名字可以一样,所以不同的用户访问同一个Border时可以创建独立的虚拟主机,然后在自己的虚拟主机中创建Exchange和Queue,实现不同用户之间的相互隔离。
- Exchange:交换机,根据分发规则,匹配查询表中的routing key,分发消息到queue中。
- Queue:队列,用来存放生产者发送的消息,消费者会将其中的消息消费掉
- Binding:Exchange和queue之间的虚拟链接,包含routing key,Binding被保存在exchange中的查询表中,作为message分发的依据
- Virtual host:虚拟主机,一个Borker中可以有对个虚拟主机,不同的虚拟主机中的exchange和queue名字可以一样,所以不同的用户访问同一个Border时可以创建独立的虚拟主机,然后在自己的虚拟主机中创建Exchange和Queue,实现不同用户之间的相互隔离。
- Connection:消费者/生产者和Broker之间的TCP连接
- Channel:消息通道,为了减少Connection连接的开销、提升效率,Channel实现了在Connection内部建立逻辑连接,可以每个线程创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message Broker识别channel,channel是完全隔离的。
exchange交换机类型
- direct:通过路由键(routing key)与队列(queue)绑定,完全匹配模式
- fanout:通过广播的形式,将消息发送给所有绑定的队列
- topic:通过对队列(routing key)的模糊绑定,进行消息传输
代码示例
导入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.13.1</version>
</dependency>
消费者代码
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建一个链接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建链接
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
DeliverCallback deliverCallback = (s,d) -> System.out.println(new String(d.getBody(), StandardCharsets.UTF_8));
CancelCallback cancelCallback = s -> System.out.println(s);
/**
* 消费消息
* 1、队列名称
* 2、是否自动应答
* 3、获取消息回调函数
* 4、取消消息回调函数
*/
channel.basicConsume("xy_queue_name1",true,deliverCallback,cancelCallback);
channel.basicConsume("xy_queue_name2",true,deliverCallback,cancelCallback);
channel.basicConsume("xy_queue_name3",true,deliverCallback,cancelCallback);
channel.basicConsume("xy_queue_name4",true,deliverCallback,cancelCallback);
channel.close();
connection.close();
}
}
direct交换机类型
消息生产者代码
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建一个链接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建链接
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
/**
* 创建交换机
* 1、交换机名称
* 2、交换机类型:direct,topic,fanout、headers
* 3、指定交换机是否需要持久化
* 4、在没有队列绑定时是否需要删除
* 5、Map类型,用来指定交换机其他的结构化参数
*/
String exchangeName = "xy_exchange_name";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,null);
/**
* 生成队列
* 1、队列名称
* 2、队列信息是否要持久化(不是队列中消息的持久化)
* 3、表示队列是否私有
* 4、在没有消费者订阅的情况下是否自动删除
* 5、队列的结构化信息
*/
String queueName1 = "xy_queue_name1";
String queueName2 = "xy_queue_name2";
String queueName3 = "xy_queue_name3";
String queueName4 = "xy_queue_name4";
channel.queueDeclare(queueName1,true,false,false,null);
channel.queueDeclare(queueName2,true,false,false,null);
channel.queueDeclare(queueName3,true,false,false,null);
channel.queueDeclare(queueName4,true,false,false,null);
/**
* 绑定交换机和队列
*/
String key1 = "key1";
String key2 = "key2";
String key3 = "key3";
String key4 = "key4";
channel.queueBind(queueName1,exchangeName,key1);
channel.queueBind(queueName2,exchangeName,key2);
channel.queueBind(queueName3,exchangeName,key3);
channel.queueBind(queueName4,exchangeName,key4);
/**
* 发送消息
* 1、要发送到哪个交换机
* 2、队列名称
* 3、其他参数信息
* 4、消息体
*/
String message = "hello rabbitmq";
channel.basicPublish(exchangeName,key1,null,message.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(exchangeName,key2,null,message.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(exchangeName,key3,null,message.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(exchangeName,key4,null,message.getBytes(StandardCharsets.UTF_8));
//关闭连接
channel.close();
connection.close();
}
}
fanout交换机类型
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建一个链接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建链接
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
/**
* 创建交换机
* 1、交换机名称
* 2、交换机类型:direct,topic,fanout、headers
* 3、指定交换机是否需要持久化
* 4、在没有队列绑定时是否需要删除
* 5、Map类型,用来指定交换机其他的结构化参数
*/
String exchangeName = "xy_exchange_name";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,null);
/**
* 生成队列
* 1、队列名称
* 2、队列信息是否要持久化(不是队列中消息的持久化)
* 3、表示队列是否私有
* 4、在没有消费者订阅的情况下是否自动删除
* 5、队列的结构化信息
*/
String queueName1 = "xy_queue_name1";
String queueName2 = "xy_queue_name2";
String queueName3 = "xy_queue_name3";
String queueName4 = "xy_queue_name4";
channel.queueDeclare(queueName1,true,false,false,null);
channel.queueDeclare(queueName2,true,false,false,null);
channel.queueDeclare(queueName3,true,false,false,null);
channel.queueDeclare(queueName4,true,false,false,null);
/**
* 绑定交换机和队列
*/
String key1 = "key1.key2.key3.*";
String key2 = "key1.#";
String key3 = "*.key2.*.key4";
String key4 = "#.key3.key4";
channel.queueBind(queueName1,exchangeName,key1);
channel.queueBind(queueName2,exchangeName,key2);
channel.queueBind(queueName3,exchangeName,key3);
channel.queueBind(queueName4,exchangeName,key4);
/**
* 发送消息
* 1、要发送到哪个交换机
* 2、队列名称
* 3、其他参数信息
* 4、消息体
*/
String message = "hello rabbitmq";
channel.basicPublish(exchangeName,"key1",null,message.getBytes(StandardCharsets.UTF_8));
//关闭连接
channel.close();
connection.close();
}
}
如果使用FANOUT,会使DIRECT和TOPIC相关的绑定配置失效
topic交换机类型
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建一个链接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建链接
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
/**
* 创建交换机
* 1、交换机名称
* 2、交换机类型:direct,topic,fanout、headers
* 3、指定交换机是否需要持久化
* 4、在没有队列绑定时是否需要删除
* 5、Map类型,用来指定交换机其他的结构化参数
*/
String exchangeName = "xy_exchange_name";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,null);
/**
* 生成队列
* 1、队列名称
* 2、队列信息是否要持久化(不是队列中消息的持久化)
* 3、表示队列是否私有
* 4、在没有消费者订阅的情况下是否自动删除
* 5、队列的结构化信息
*/
String queueName1 = "xy_queue_name1";
String queueName2 = "xy_queue_name2";
String queueName3 = "xy_queue_name3";
String queueName4 = "xy_queue_name4";
channel.queueDeclare(queueName1,true,false,false,null);
channel.queueDeclare(queueName2,true,false,false,null);
channel.queueDeclare(queueName3,true,false,false,null);
channel.queueDeclare(queueName4,true,false,false,null);
/**
* 绑定交换机和队列
*/
String key1 = "key1.key2.key3.*";
String key2 = "key1.#";
String key3 = "*.key2.*.key4";
String key4 = "#.key3.key4";
channel.queueBind(queueName1,exchangeName,key1);
channel.queueBind(queueName2,exchangeName,key2);
channel.queueBind(queueName3,exchangeName,key3);
channel.queueBind(queueName4,exchangeName,key4);
/**
* 发送消息
* 1、要发送到哪个交换机
* 2、队列名称
* 3、其他参数信息
* 4、消息体
*/
String message = "hello rabbitmq";
channel.basicPublish(exchangeName,"key1",null,message.getBytes(StandardCharsets.UTF_8));
//关闭连接
channel.close();
connection.close();
}
}