基础架构图
-
- Producer:生产者
- Consumer:消费者
- Broker:RabbitMQ Server
- Virtual host:每个用户对应一个vhost
- Connection:TCP连接
- Channel:在Connection内部建立的逻辑连接,极大减少了操作系统建立TCP连接的开销
- Exchange:交换机
- Queue:队列
简单模式
引入依赖
<!-- rabbitmq 依赖客户端 --> <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.16.0</version> </dependency> <!-- 操作文件流的依赖 --> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
生产者
package com.wyk.rabbitmq.one;
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 {
//队列名称
public static final String QUEUE_NAME = "hello";
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 工厂IP 连接RabbitMQ的队列
factory.setHost("121.40.241.131");
//端口
factory.setPort(5672); //默认值
// 用户名
factory.setUsername("admin");
// 密码
factory.setPassword("123");
// 创建连接
Connection connection = factory.newConnection();
// 获取信道
Channel channel = connection.createChannel();
/*
生成一个队列
参数:
队列名称
队列里面的消息是否需要持久化(磁盘)默认存储在内存中
该队列是否只供一个消费者消费 是否进行消息的共享 true表示多个 false表示一个 默认为false
是否自动删除 最后一个消费者断开连接后 该队列是否自动删除 true自动删除 false不自动删除
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
// 发消息
String message = "hello world";
/*
* 发送一个消息
* 参数:
* 发送到那个交换机 简单模式使用默认的
* 路由的KEY值 使用默认交换机时routingKey为队列的名称
* 其他参数消息
* 发送消息的消息体
*/
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
System.out.println("消息发送完毕");
}
}
消费者
package com.wyk.rabbitmq.one;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;
public class Consumer {
// 队列名称
public static final String QUEUE_NAME = "hello";
// 接收消息
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置ip
connectionFactory.setHost("121.40.241.131");
// 设置用户名和密码
connectionFactory.setUsername("admin");
connectionFactory.setPassword("123");
// 生成连接
Connection connection = connectionFactory.newConnection();
// 获取信道
Channel channel = connection.createChannel();
/**
* 接收消息
* 参数
* 消费哪个队列
* 消费成功之后是否要自动应答 true表示自动应答
* 消费者成功消费的回调
* 消费者消费失败的回调
*/
channel.basicConsume(QUEUE_NAME,true,(c,m) ->{
System.out.println(Arrays.toString(m.getBody()));
},c->{
System.out.println("消息消费被中断");
});
}
}
WorkQueues 工作队列模式
消费者之间是"竞争"的关系,一条消息只能由一个消费者消费
与简单模式差不多,多开几个消费者就行了
Work Queues对于任务过重或任务多情况可以使用工作队列提高任务处理的速度。
例如:短信服务部署多个只需要一个节点发送成功即可
Pub/Sub 发布/订阅模式
一条消息可被多个消费者消费
- P:生产者,发送消息给交换机(X)
- C:消费者,接收消息、缓存消息,从队列获取
- Queue:消息队列,接收消息、缓存消息
- Exchange:交换机(X),一方面,接收生产者发送的消息,另一方面,根据交换机类型处理数据(传递给某个队列、传递给所有队列或丢弃消息)
- exchange类型:
- Fanout:广播,将消息交给所有绑定到交换机的队列
- Direct:定向,把消息交给指定的routing key的队列
- Topic:通配符,把消息交给符合Routing pattern(路由模式)的队列
- Headers:参数匹配
- exchange 只负责转发消息,不具备存储消息的能力,因此当没有队列与exchange绑定,或没有符合路由规则的队列时,消息将会丢失
- exchange类型:
生产者代码
package com.wyk.rabbitmq.producer;
import com.rabbitmq.client.BuiltinExchangeType;
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 ProducerPubSub {
//队列名称
public static final String QUEUE_NAME1 = "queue1";
public static final String QUEUE_NAME2 = "queue2";
public static final String EXCHANGE_NAME = "test_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 工厂IP 连接RabbitMQ的队列
factory.setHost("121.40.241.131");
// 用户名
factory.setUsername("admin");
// 密码
factory.setPassword("123");
// 创建连接
Connection connection = factory.newConnection();
// 获取信道
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME1,false,false,false,null);
channel.queueDeclare(QUEUE_NAME2,false,false,false,null);
/**
* public DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable,
* boolean autoDelete, boolean internal, Map<String, Object> arguments) throws IOException
* 创建交换机
* 参数:
* 交换机名称
* 交换机类型
* 是否持久化
* 自动删除
* 是否内部使用
* 参数列表
*/
// fanout 广播交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT,true,false,false,null);
/**
* queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments)
* 绑定队列和交换机
* 参数:
* 队列名称
* 交换机名称
* 路由key: 绑定规则,不同类型交换机根据路由key转发消息,广播交换机不需要routing key 因为是广播所有人都能收到
* 参数列表
*/
channel.queueBind(QUEUE_NAME1, EXCHANGE_NAME,"");
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,"");
String body = "日志信息:调用***方法...日志级别:info...";
channel.basicPublish(EXCHANGE_NAME,"",null,body.getBytes());
System.out.println("消息发送完毕");
}
}
消费者代码
package com.wyk.rabbitmq.consumer;
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 ConsumerPubSub1 {
// 队列名称
public static final String QUEUE_NAME = "queue1";
// 接收消息
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置ip
connectionFactory.setHost("121.40.241.131");
// 设置用户名和密码
connectionFactory.setUsername("admin");
connectionFactory.setPassword("123");
// 生成连接
Connection connection = connectionFactory.newConnection();
// 获取信道
Channel channel = connection.createChannel();
channel.basicConsume(QUEUE_NAME, true, (c, m) -> {
System.out.println(new String(m.getBody()));
}, c -> {
System.out.println("消息消费被中断");
});
}
}
routing 路由模式
生产者
// 不同的代码
// direct 定向
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT,true,false,false,null);
channel.queueBind(QUEUE_NAME1, EXCHANGE_NAME,"error");
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,"error");
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,"warning");
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,"info");
Topics 通配符模式
生产者
// topics 通配符
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC,true,false,false,null);
// 绑定路由key、队列、交换机 * 匹配一个单词 # 匹配0到多个单词
channel.queueBind(QUEUE_NAME1, EXCHANGE_NAME,"#.error");
channel.queueBind(QUEUE_NAME1, EXCHANGE_NAME,"order.#");
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,"*.*");