一、Rabbitmq简介
1.1 rabbitmq 架构
1.2 rabbitmq相关组件介绍
- exchange: 交换机,主要用来将生产者发送的消息路由给服务器中的队列。
- routing-key: 消息路由的key,生产者在将消息发到到exchange的时候,需要指定routing-key,这样exchange才知道将这条消息路由给哪些队列。
- message: 消息体,主要由消息头和消息body组成,消息头包括是否持久化,routing-key等。
- binding 将消息队列和exchange进行绑定,一个绑定就是基于路由键将交换机和消息队列连接起来。
- publisher: 消息生产者,可以理解为一个发送消息的客户端应用程序。
- consumer: 消息消费者,可以理解为一个从queue消费消息的应用程序。
- queue : 消息队列,用来保存消息直到发送给消费者,相当于一个容器,一个容器可以放N条消息等待被消费。
- channel : 通道,不管是发送消息还是订阅消息都是通过通道发送出去的,相当于复用TCP连接,因为每次都创建一个TCP连接时非常耗资源的。
1.3 rabbimq常用的3种exchange
1.3.1 fanout exchange
不处理路由键,你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。

1.3.2 direct exchange
处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。
1.3.3 topic exchange
将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。比如符号”#”匹配一个或多个词

1.4 rabbitmq消息的可靠传输
一般对于业务不允许由消息丢失的场景来说,消息需要保证被至少传输一次(消费端做幂等),在rabbitmq里面,可能存在几种情况,消息会出现丢失,
- 生产者弄丢了消息,即生产者在将消息发送到exchange的过程中,可能由于网络等原因半路就丢失了,这个时候可以采用rabbitmq的事务机制,也就是在消息发送之前,开启事务,如果没有发送到exchange,生产者收到报错后回滚事务,然会重新发送,如果消息正常到达,则提交事务。但是事务相当于同步操作,整体性能不高,所以一般在生产端建议开启Confirm机制。
- rabbitmq丢了消息,这个时候需要开启rabbitmq的持久化功能,首先是队列开启持久化,同时发送的消息的deliveryMode也设置为持久的,这样,消息就会持久化到磁盘了,即使rabbitmq挂了,重启后也能恢复数据,配合客户端的confirm机制,就算是在还没持久化到磁盘之前,rabbitmq挂了,生产者会重发,在重试次数范围内,只要持久化到磁盘了,就会返回ack。
- 消费者丢了消息,这个需要关闭rabbitmq的自动ack功能,因为自动ack的话,只要消费者收到了就会ack,并不关心消费者是否成功消费, 消费者ack需要由应用自己决定什么时候返回ack。
二、Demo演示
2.1 maven导入rabbitmq依赖包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- rabbitmq starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
2.2 新建application
package com.yunsom.springboot.rabbitmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootMessageApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMessageApplication.class, args);
}
}
2.3 新建rabbitmq配置文件
在springboot里面,因为使用了其封装好的rabbitmq,在实际的开发中,根据不同的exchange模式,需要自己申明不同的exchange,下面以direct exchange模式为例子进行说明
package com.yunsom.springboot.rabbitmq.config;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfig {
/**
* 死信队列 交换机标识符
*/
private static final String DEAD_LETTER_QUEUE_KEY = "x-dead-letter-exchange";
/**
* 死信队列交换机绑定键标识符
*/
private static final String DEAD_LETTER_ROUTING_KEY = "x-dead-letter-routing-key";
/**
* 死信队列里面消息的超时时间
*/
private static final String X_MESSAGE_TTL = "x-message-ttl";
/**
* 声明交换机,支持持久化.
* rabbitmq常用几种exchange,比如direct, fanout, topic,可根据具体业务需求配置
* 命名规范参考 scm3.services,scm3.services.retry,scm3.services.failed
* @return the exchange
*/
@Bean("scm3.materials")
public Exchange directExchange() {
//.durable(true) exchange的持久化
return ExchangeBuilder.directExchange("scm3.materials").du