同步调用
时效性强
拓展性差
性能下降
级联失败
异步调用
业务解耦,拓展性强
无需等待,性能好
故障隔离
缓存信息,流量削峰填谷
时效性差
不确定执行是否成功
linux环境,用docker安装
下载rabbitmq镜像
docker pull rabbitmq:3.7.15
创建容器
docker run -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -v mq-plugins:/plugins --name rabbitmq --hostname myrabbitmq -p 15672:15672 -p 5672:5672 -d rabbitmq:3.7.15
查看容器
docker ps
配置管理页面插件
docker exec -it rabbitmq /bin/bash
rabbitmq-plugins enable rabbitmq_management
访问管理页面ip:15672,账号密码为创建容器的RABBITMQ_DEFAULT信息
publisher:消息发送者
consumer:消息消费者
queue:队列,负责存储消息
exchange:交换机,负责路由转发消息
virtual-host:虚拟主机,负责数据隔离
高级消息队列协议
Spring AMQP:基于AMQP协议定义的一套API规范
rabbitmq管理页面创建队列testQueue
微服务项目,引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
配置rabbitmq信息
spring:
rabbitmq:
host: ip
port: 5672
virtual-host: /
username: username
password: password
发送,用单元测试
@SpringBootTest(classes = UserApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void test() {
String queue = "testQueue";
String message = "hello";
rabbitTemplate.convertAndSend(queue, message);
}
}
接收
@Component
public class MqListener {
@RabbitListener(queues = "testQueue")
public void listen(String message) {
System.out.println("msg=" + message);
}
}
rabbitmq管理页面创建队列workQueue
多个消费者绑定到一个队列,加快消息处理速度
同一条消息只会被一个消费者处理
设置prefetch控制消费者预取消息数量
消费者配置
spring:
rabbitmq:
listener:
simple:
prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一条
发送
@Test
void testWorkQueue() {
String queue = "workQueue";
for (int i = 1; i <= 50; i++) {
String message = "hello" + i;
rabbitTemplate.convertAndSend(queue, message);
}
}
接收
@RabbitListener(queues = "workQueue")
public void listenWorkQueue1(String message) throws InterruptedException {
System.out.println("listen1,msg=" + message);
Thread.sleep(20);
}
@RabbitListener(queues = "workQueue")
public void listenWorkQueue2(String message) throws InterruptedException {
System.out.println("listen2,msg=" + message);
Thread.sleep(200);
}
listen1处理速度更快,因此处理消息数量更多
广播模式,分发每个队列
rabbitmq管理页面创建队列q1,q2,绑定amq.fanout交换机
发送
@Test
void testFanout() {
String exchange = "amq.fanout";
String message = "hello fanout";
rabbitTemplate.convertAndSend(exchange, "", message);
}
接收
@RabbitListener(queues = "q1")
public void listenFanout1(String message) {
System.out.println("listenfanout1,msg=" + message);
}
@RabbitListener(queues = "q2")
public void listenFanout2(String message) {
System.out.println("listenfanout2,msg=" + message);
}
定向路由,每个队列绑定交换机时设置一个routingKey,发送消息指定routingKey发送到指定队列
rabbitmq管理页面创建队列directQueue1,directQueue2,分别绑定amq.direct交换机,设置routingKey为direct1,direct2
发送
@Test
void testDirect() {
String exchange = "amq.direct";
String message = "hello direct";
String routingKey = "direct1";
rabbitTemplate.convertAndSend(exchange, routingKey, message);
}
接收
@RabbitListener(queues = "directQueue1")
public void listenDirect1(String message) {
System.out.println("listenDirect1,msg=" + message);
}
@RabbitListener(queues = "directQueue2")
public void listenDirect2(String message) {
System.out.println("listenDirect2,msg=" + message);
}
与Direct类似,routingKey可以是多个单词的列表,以.分割,routingKey可以指定通配符
#:0个或多个单词
*:一个单词
rabbitmq管理页面创建队列topicQueue1,topicQueue2,分别绑定amq.topic交换机,设置routingKey为topic1.#,topic2.#
发送
@Test
void testTopic() {
String exchange = "amq.topic";
String message = "hello topic";
String routingKey = "topic1.aaa";
rabbitTemplate.convertAndSend(exchange, routingKey, message);
}
接收
@RabbitListener(queues = "topicQueue1")
public void listenTopic1(String message) {
System.out.println("listenTopic1,msg=" + message);
}
@RabbitListener(queues = "topicQueue2")
public void listenTopic2(String message) {
System.out.println("listenTopic2,msg=" + message);
}
@Configuration
public class FanoutConfig {
@Bean
public FanoutExchange fanoutExchange() {
// 二选一
// return ExchangeBuilder.fanoutExchange("myFanout");
return new FanoutExchange("myFanout");
}
@Bean
public Queue queue() {
// 二选一
// return QueueBuilder.durable("myQueue");
return new Queue("myQueue");
}
@Bean
public Binding binding(Queue queue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queue).to(fanoutExchange);
}
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "myQueue", durable = "true"),
exchange = @Exchange(name = "myDirect", type = ExchangeTypes.DIRECT),
key = {"red"}
))
public void listenDirect(String message) {
System.out.println("listenDirect,msg=" + message);
}
创建队列objectQueue
发送java对象或者map
引入依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
dependency>
发送方、接收方添加消息转换器
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
发送
@Test
void testSendObject() {
String queue = "objectQueue";
Map<String, Object> map = new HashMap<>();
map.put("id", "1");
map.put("name", "hhh");
rabbitTemplate.convertAndSend(queue, map);
}
接收
@RabbitListener(queues = "objectQueue")
public void listenObject(Map<String, Object> map) {
System.out.println("listenObject,msg=" + map);
}
其它消息队列知识看JavaGuide 消息队列