一.关于RabbitMQ
1.RabbitMQ交换机类型
(1).FanoutExchange:广播交换机。消息发送到交换机后,会广播到所有队列,不需要经过路由。
(2).DirectExchange:直通交换机。生产者发送消息到交换机(Exchange),再经过路由(Routing Key),发送到绑定的队列(Queue),消费者接收队列消息。
(3).TopicExchange:交换机可以把消息绑定到匹配一个关键字(*),0个或多个关键字(#)的路由。
2.RabbitMQ确认消费机制
(1).生产者确认消息是否成功发送。
(2).消费者确认消息不丢失和被确认消费。
二.RabbitMQ实战
1.RabbitMQ的使用场景
(1)商品扣库存或者秒杀场景,前端的请求按顺序进入RabbitMQ普通队列中,再按顺序消费,实现某种程度的限流。这种适用于异步通知结果,类似大麦网预约抢票。
(2)用户下单后,将订单信息发送到RabbitMQ普通队列,异步将订单信息写入数据库。RabbitMQ普通队列消息设置过期不消费放入死信队列,不监听普通队列,监听死信队列,处理没有在指定时间付款的订单数据。
2.搭建SpringBoot项目
(1)maven pom文件
引入SpringBoot、AMQP、MyBatis-Plus、Redis等组件。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-boot-dependencies.version>2.3.12.RELEASE</spring-boot-dependencies.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
(2)yaml文件
包含Redis、RabbitMQ、数据库连接、交换机/队列/路由名称配置。
server:
port: 8089
shutdown: graceful
spring:
application:
name: rabbitMq
redis:
port: 31091
host: 112.74.54.29
password:
timeout: 600000
datasource:
password: root
username: root
url: jdbc:mysql://x.x.x.x:31090/rabbit_mq?useUnicode=true;characterEncoding=UTF-8&nullCatalogMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
# type: com.alibaba.druid.pool.DruidDataSource
# name: druidDataSource
rabbitmq:
virtual-host: /
host: 127.0.0.1
port: 5672
username: guest
password: guest
publisher-confirm-type: correlated
listener:
simple:
acknowledge-mode: manual
template:
mandatory: true
rabbitmq:
seckill:
queue:
name: rabbitmq.seckill.queue
exchange:
name: rabbitmq.seckill.exchange
routing:
key:
name: rabbitmq.seckill.routing.key
dead:
queue:
name: rabbitmq.seckill.dead.queue
exchange:
name: rabbitmq.seckill.dead.exchange
routing:
key:
name: rabbitmq.seckill.dead.routing.key
logging:
level:
org:
springframework:
jdbc:
core:
JdbcTemplate: DEBUG
web:
servlet:
DispatcherServlet: DEBUG
mybatis-plus:
mapper-locations: mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
type-aliases-package: gdut.entity
(3)RabbitMQ配置
定义RabbitMQ发送消费消息配置。创建普通交换机、普通队列、关联普通交换机和普通队列的路由、死信交换机、死信队列、关联死信交换机和死信队列的路由。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.util.HashMap;
@Configuration
public class RabbitMQConfiguration {
private static final Logger log = LoggerFactory.getLogger(RabbitMQConfiguration.class);
@Autowired
private Environment environment;
@Bean
public RabbitTemplate rabbitTemplate(CachingConnectionFactory factory) {
log.info("rabbitTemplate factory is:{}", factory.getChannelCacheSize());
RabbitTemplate rabbitTemplate = new RabbitTemplate(factory);
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if(ack) {
log.info("rabbitTemplate success correlationData is:{}, b is:{}, s is:{}", correlationData, ack, cause);
} else {
log.info("rabbitTemplate failed correlationData is:{}, b is:{}, s is:{}", correlationData, ack, cause);
}
}
});
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2)