文章目录
rabbitmq的五种常用模式
官方网址
https://www.rabbitmq.com/getstarted.html
创建idea的maven项目
因为五种方式的结构一样,这边我就创建一个项目作为演示
(1)创建一个大的maven项目当作父项目
(2)选择安装路径
(3)在父项目下创建连个子项目
创建步骤和父项目一样
(4)效果展示
(5)引入依赖
maven项目有一个特性,子类工程可以继承父类工程引得依赖
(1)简单模式
从图上可以看到只有三个角色:
p 【product】: 生产者 发生消息的
红色[queue]: 队列。 存储消息的
C [consumer]: 消费者 消费消息
生产者(往队列中加入信息)
public class Product {
public static void main(String[] args)throws Exception {
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
//虚拟机的IP
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//创建队列
/**
* String queue, 队列的名称
* boolean durable, 是否该队列持久化 rabbitMQ服务重启后该存放是否存在。
* boolean exclusive, 是否独占 false
* boolean autoDelete, 是否自动删除 如果长时间没有发生消息 则自动删除
* Map<String, Object> arguments 额外参数 先给null
*/
channel.queueDeclare("ban129_queue",true,false,false,null);
//发生消息
/**
* String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
* String routingKey, 路由key 如果没有交换机的绑定 使用队列的名称
* BasicProperties props, 消息的一些额外配置 目前先不加 null
* byte[] body 消息的内容
*/
String msg="holle!!!!!!!!!!!";
channel.basicPublish("","ban129_queue",null,msg.getBytes());
}
}
消费者(消费队列信息)
public class Consumer {
public static void main(String[] args) throws Exception{
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接受消息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer callback=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//body 接受的信息
System.out.println("消息的内容:"+new String(body));
}
};
channel.basicConsume("ban129_queue",true,callback);
}
}
测试
- [1 ] 先运行生产者
- [2 ]运行消费者
(2)工作者模式
特点:
1. 一个生产者
2. 由多个消费。
3. 统一个队列。
4. 这些消费者之间存在竞争关系。
用处: 比如批量处理上. rabbitMQ里面积压了大量的消息。
生产者(往队列中加入信息)
public class Product {
public static void main(String[] args)throws Exception {
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//创建队列
/**
* String queue, 队列的名称
* boolean durable, 是否该队列持久化 rabbitMQ服务重启后该存放是否存在。
* boolean exclusive, 是否独占 false
* boolean autoDelete, 是否自动删除 如果长时间没有发生消息 则自动删除
* Map<String, Object> arguments 额外参数 先给null
*/
channel.queueDeclare("ban129_queue_work",true,false,false,null);
//发生消息
/**
* String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
* String routingKey, 路由key 如果没有交换机的绑定 使用队列的名称
* BasicProperties props, 消息的一些额外配置 目前先不加 null
* byte[] body 消息的内容
*/
for(int i=0;i<10;i++) {
String msg = "冯昱凯真帅!!!!!!!!!!!"+i;
channel.basicPublish("", "ban129_queue_work", null, msg.getBytes());
}
//生产者这里可以管理资源 消费者不能关闭资源。
channel.close();
connection.close();
}
}
消费者01(消费队列信息)
public class Consumer01 {
public static void main(String[] args) throws Exception{
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接受消息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer callback=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//body 接受的信息
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者01:"+new String(body));
}
};
channel.basicConsume("ban129_queue_work",true,callback);
}
}
消费者02(消费队列信息)
public class Consumer02 {
public static void main(String[] args) throws Exception{
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接受消息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer callback=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//body 接受的信息
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者01:"+new String(body));
}
};
channel.basicConsume("ban129_queue_work",true,callback);
}
}
测试
- [1 ] 先运行生产者
- [2 ]运行消费者01
- [3 ]运行消费者02
总结
可以看到,在生产者往队列中加入100条信息后,消费者01(consumer1)和消费者02(consumer2)是采用交替处理的方式进行消费队列中的信息的
(3)发布订阅模式
特点:
1.一个生产者
2.多个消费者
3.多个队列。
4.交换机 转发消息。
生产者(往队列中加入信息)
public class product1 {
public static void main(String[] args) throws Exception{
//创建工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.11.222");
//获取对象
Connection connection = connectionFactory.newConnection();
//创建信道
Channel channel = connection.createChannel();
/**
* (String queue, 队列的名称
* boolean durable, 是否持久化
* boolean exclusive, 是否独占
* boolean autoDelete, 是否自动销毁
* Map<String, Object> arguments 额外参数 不用就给空 null
*/
channel.queueDeclare("ban129_fanout01",true,false,false,null);
channel.queueDeclare("ban129_fanout02",true,false,false,null);
//创建交换机
/**
* String exchange,交换机的名称
* BuiltinExchangeType type, 交换机的类型
* boolean durable:是否持久化
*/
channel.exchangeDeclare("ban129_exchange", BuiltinExchangeType.FANOUT,true);
//绑定交换机和队列
/**
* String queue, 队列名
* String exchange, 交换机的名称
* String routingKey:路由key 如果交换机为fanout模式则不需要路由key
*/
channel.queueBind("ban129_fanout01","ban129_exchange","");
channel.queueBind("ban129_fanout02","ban129_exchange","");
//发生消息
/**
* String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
* String routingKey, 路由key 如果没有交换机的绑定 使用队列的名称
* BasicProperties props, 消息的一些额外配置 目前先不加 null
* byte[] body 消息的内容
*/
for (int i = 0; i < 15; i++) {
String msg = "刘亚飞真帅,好像没有见过他说话!!!!!!!!!!!"+i;
channel.basicPublish("ban129_exchange","",null,msg.getBytes());
}
}
}
消费者01(消费队列信息)
public class Consumer1 {
public static void main(String[] args) throws Exception{
//创建 连接对象
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.222");
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接受信息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer consumer= new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ababab1"+new String(body));
}
};
channel.basicConsume("ban129_fanout01",true,consumer);
}
}
消费者02(消费队列信息)
public class Consumer2 {
public static void main(String[] args) throws Exception{
//创建 连接对象
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.222");
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接受信息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer consumer= new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ababab2"+new String(body));
}
};
channel.basicConsume("ban129_fanout02",true,consumer);
}
}
测试
- [1 ] 先运行生产者
- [2 ]运行消费者01
- [3 ]运行消费者02
总结
可以看到,在生产者往队列中加入15条信息后,队列1和队列2都接收到信息并存储信息,消费者01(consumer1)和消费者02(consumer2)对应不同的队列,都可以消费生产者发布的信息
(4)路由模式
特点:
1.一个生产者
2.多个消费者
3.多个队列。
4.交换机 转发消息。
5.routekey:路由key 只要routekey匹配的消息可以到达对应队列。
生产者(往队列中加入信息)
public class Product1 {
public static void main(String[] args) throws Exception{
//创建连接
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.222");
//获得对象
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
/**
* String queue,队列的名称
* boolean durable,是否持久化
* boolean exclusive, 是否独占
* boolean autoDelete, 是否自动删除
* Map<String, Object> arguments 额外参数
*/
channel.queueDeclare("ban129_queue_direct01",true,false,false,null);
channel.queueDeclare("ban129_queue_direct02",true,false,false,null);
//创建交换机
/**
* String exchange,交换机的名称
* BuiltinExchangeType type, 交换机的类型
* boolean durable:是否持久化
*/
channel.exchangeDeclare("ban129_exchange_direct", BuiltinExchangeType.DIRECT,true);
/**
* String queue, 队列名
* String exchange, 交换机的名称
* String routingKey:路由key 如果交换机为fanout模式则不需要路由key
*/
//绑定队列的路由key
channel.queueBind("ban129_queue_direct01","ban129_exchange_direct","error");
channel.queueBind("ban129_queue_direct02","ban129_exchange_direct","error");
channel.queueBind("ban129_queue_direct02","ban129_exchange_direct","info");
channel.queueBind("ban129_queue_direct02","ban129_exchange_direct","wange");
/**
* String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
* String routingKey, 路由key 如果没有交换机的绑定 使用队列的名称
* BasicProperties props, 消息的一些额外配置 目前先不加 null
* byte[] body 消息的内容
*/
//发送消息
for (int i = 0; i < 20; i++) {
String msg= "加油"+i;
channel.basicPublish("ban129_exchange_direct","error",null,msg.getBytes());
channel.basicPublish("ban129_exchange_direct","info",null,msg.getBytes());
// channel.basicPublish("ban129_exchange_direct","error",null,msg.getBytes());
}
}
}
消费者01(消费队列信息)
public class Consumer1 {
public static void main(String[] args) throws Exception{
//创建连接
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.222");
//获得对象
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接收信息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer consumer= 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("ban129_queue_direct01",true,consumer);
}
}
消费者02(消费队列信息)
public class Consumer2 {
public static void main(String[] args) throws Exception{
//创建连接
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.222");
//获得对象
Connection connection = factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//接收信息
/**
* (String queue, 队列的名称
* boolean autoAck, 是否自动确认
* Consumer callback: 回调方法 当队列中存在信息后 会自动触发回调函数。
*/
DefaultConsumer consumer= 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("ban129_queue_direct02",true,consumer);
}
}
测试
-
[1 ] 先运行生产者
-
[2 ]运行消费者01
-
[3 ]运行消费者02
总结
可以看到,在生产者代码中给两个队列绑定了不同的路由key,在交换机往队列发信息时带了不同的路由key,只有队列绑定了此key才能成功往此队列发送信息。
(5)topic主体模式
整体代码于路由模式基本一样,只是交换机在绑定路由key时使用了通配符
1. 绑定按照通配符的模式。
*: 统配一个单词。
#: 统配n个单词
生产者
public class Product {
public static void main(String[] args)throws Exception {
//创建连接工厂 --配置连接信息
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.213.188");
//创建连接对象Connection
Connection connection=factory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//创建队列
/**
* String queue, 队列的名称
* boolean durable, 是否该队列持久化 rabbitMQ服务重启后该存放是否存在。
* boolean exclusive, 是否独占 false
* boolean autoDelete, 是否自动删除 如果长时间没有发生消息 则自动删除
* Map<String, Object> arguments 额外参数 先给null
*/
channel.queueDeclare("ban129_queue_topic01",true,false,false,null);
channel.queueDeclare("ban129_queue_topic02",true,false,false,null);
//创建交换机
/**
* String exchange,交换机的名称
* BuiltinExchangeType type, 交换机的类型
* boolean durable:是否持久化
*/
channel.exchangeDeclare("ban129_exchange_topic", BuiltinExchangeType.TOPIC,true);
/**
* String queue, 队列名
* String exchange, 交换机的名称
* String routingKey:路由key 如果交换机为fanout模式则不需要路由key
*/
//在绑定路由key时使用通配符 # 和 *
channel.queueBind("ban129_queue_topic01","ban129_exchange_topic","*.orange.*");
channel.queueBind("ban129_queue_topic02","ban129_exchange_topic","*.*.rabbit");
channel.queueBind("ban129_queue_topic02","ban129_exchange_topic","lazy.#");
//发生消息
/**
* String exchange: 交换机的名称 如果没有则使用“” 它回自动采用默认
* String routingKey, 路由key 如果没有交换机的绑定 使用队列的名称
* BasicProperties props, 消息的一些额外配置 目前先不加 null
* byte[] body 消息的内容
*/
for(int i=0;i<10;i++) {
String msg = "你们有没有打疫苗!!!!!!!!!!!"+i;
channel.basicPublish("ban129_exchange_topic", "lazy.orange.rabbit", null, msg.getBytes());
}
//生产者这里可以管理资源 消费者不能关闭资源。
channel.close();
connection.close();
}
}
总结
在生产者代码中使用通配符给两个队列绑定了不同的路由key,在交换机往队列发信息时带了不同的路由key,只有队列绑定了此key才能成功往此队列发送信息。