为了保证消息不丢失,从生产者两种模式(确认模式和返回模式)到消费者手动确认的一个大整合
生产者
1.maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<!-- 用于rabbitmq发送json消息 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.配置文件yml
server:
port: 8001
spring:
rabbitmq:
host: 192.168.56.101
port: 5672
virtual-host: /ems
username: admin
password: admin
# 开启确认模式
publisher-confirms: true
# 开启回退模式
publisher-returns: true
3.编写rabbitmq配置类RabbitmqConfig,包含交换机、队列、绑定队列与交换机、设置确认模式和返回模式以及消息转换器
/**
* @author xiaozikang
* @date 2020/10/10 11:02
* @Email:xiaozikangwy@163.com
*/
@Configuration
public class RabbitmqConfig {
public static final String CONFIRM_EXCAHNGE = "confirmExchange";
public static final String CONFIRM_QUEUE = "confirmQueue";
// 交换机
@Bean("confirmExchange")
public Exchange confirmExchange(){
return ExchangeBuilder.directExchange(CONFIRM_EXCAHNGE).durable(true).build();
}
// 队列
@Bean("confirmQueue")
public Queue confirmQueue(){
return QueueBuilder.durable(CONFIRM_QUEUE).build();
}
// 绑定队列与交换机
@Bean
public Binding binding(
@Qualifier("confirmQueue") Queue confirmQueue,
@Qualifier("confirmExchange") Exchange confirmExchange
){
return BindingBuilder.bind(confirmQueue).to(confirmExchange).with("confirm").noargs();
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
// 定义消息转换器Jackson2JsonMessageConverter,发送json数据
rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
// 设置开启Mandatory,如果消息没路由到队列,则返回给消息发送方(如果不开启,默认丢弃消息)
rabbitTemplate.setMandatory(true);
// 定义确认模式
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
/**
* correlationData 相关配置信息
* ack exchange交换机是否成功收到了消息,true成功
* cause 失败原因
*/
if (ack){
System.out.println("exchange成功收到消息");
}else {
System.out.print("未收到消息:" + cause);
// 可以做些处理,再次发送
}
}
});
// 定义返回模式
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
/**
* message 消息对象
* replyCode 错误码
* replyText 错误信息
* exchange 交换机
* routingKey 路由键
*/
System.out.println("回调函数执行了");
}
});
return rabbitTemplate;
}
@Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter(){
return new Jackson2JsonMessageConverter();
}
}
4.实体类(主要用于测试发送json消息)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private String name;
private Integer age;
}
5.发送消息
@Test
public void testf01(){
User user = new User("小明",10);
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend(RabbitmqConfig.CONFIRM_EXCAHNGE,"confirm",user);
}
}
消费者
1.maven依赖
<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>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.5</version>
</dependency>
2.配置文件yml
server:
port: 9020
spring:
rabbitmq:
host: 192.168.56.101
port: 5672
virtual-host: /ems
username: admin
password: admin
listener:
simple:
# 消费手动确认
acknowledge-mode: manual
# 消费者每次从队列获取的消息数量。此属性当不设置时为:轮询分发,设置为1为:公平分发
prefetch: 2
# 指定最小的消费者数量
# concurrency: 1
# 指定最大的消费者数量
# max-concurrency: 2
3.编写配置类(这边主要用于接受json类型消息)
/**
* @author xiaozikang
* @date 2020/10/12 17:50
* @Email:xiaozikangwy@163.com
*/
@Configuration
public class RabbitConfig implements RabbitListenerConfigurer {
@Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
}
@Bean
MessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory messageHandlerMethodFactory = new DefaultMessageHandlerMethodFactory();
messageHandlerMethodFactory.setMessageConverter(consumerJackson2MessageConverter());
return messageHandlerMethodFactory;
}
@Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
}
4.消费消息
@Component
public class Consumer {
@RabbitListener(queues = "confirmQueue")
public void process(User user, Channel channel, Message message) throws IOException {
// 1.接受转换消息
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
// 2.处理业务逻辑
System.out.println("处理业务逻辑。。。。。。");
// 3.手动签收
// channel.basicAck(deliveryTag,true);
} catch (Exception e) {
// e.printStackTrace();
// 4.出现异常,拒绝签收
/**
* requeue 重回队列
* multiple false只确认当前consumer一个消息收到,true确认所有consumer获得的消息
*/
channel.basicNack(deliveryTag,true,true);
}
}
}