1.发送消息到mq,保证消息必达
package com.producer.mq;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class SendService implements RabbitTemplate.ConfirmCallback{
@Autowired
RabbitTemplate rabbitTemplate;
String msgService = null;
//发送MQ消息方法
public void send(String msg,String token) {
msgService = msg;
// 封装消息,手动签收必须封装
Message message = MessageBuilder.withBody(msg.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setContentEncoding("utf-8").setMessageId(token).build();
// 构建回调返回的数据
CorrelationData correlationData = new CorrelationData(token);
// 发送消息
this.rabbitTemplate.setMandatory(true);
this.rabbitTemplate.setConfirmCallback(this);
log.info("发送消息mq==========>>"+message);
rabbitTemplate.convertAndSend("UserExchange", "UserRouting", message, correlationData);
}
//MQ确认应答机制
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
String token = correlationData.getId();
log.info("消息id:" + correlationData.getId());
if (ack) {
log.info("MQ确认应答机制:消息发送确认成功");
} else {
//重试机制
send(msgService,token);
log.info("MQ确认应答机制:消息发送确认失败:" + cause);
}
}
}
2.消费MQ消息,保证消息正常消费,采用手动签收。
package com.producer.listener;
import java.io.IOException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class RabbitListenerService {
@RabbitListener(queues = "UserQueue")
@RabbitHandler
public void process(Message message,Channel channel) throws Exception {
byte[] msg = message.getBody();
String messageId = message.getMessageProperties().getMessageId();
log.info("UserQueue消费者收到消息---->>" + new String(msg));
log.info("messageId消息ID---->>" + messageId);
try {
//int a = 1/0;
// 手动签收消息,通知mq服务器端删除该消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
log.info("手动签收成功================================》》");
} catch (IOException e) {
e.printStackTrace();
// 丢弃该消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
log.error(" 丢弃该消息==============并对user服务做补偿==================》》");
}
}
}
3.MQ配置文件
# 消息确认:手动签收
spring.rabbitmq.listener.simple.acknowledge-mode=manual
# 开启自动重试
spring.rabbitmq.listener.simple.retry.enabled=true
# 最大重试次数
spring.rabbitmq.listener.simple.retry.max-attempts=5
# 重试时间间隔
spring.rabbitmq.listener.simple.retry.initial-interval=3000