一、设置消费者拦截器
继承 Listener容器 SimpleRabbitListenerContainerFactory 实现类
/**
* 设置下消费者拦截器
*/
@Bean
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,
AfterReceiveMessagePostProcessor afterReceiveMessagePostProcessor) {
LoggedSimpleRabbitListenerContainerFactory factory = new LoggedSimpleRabbitListenerContainerFactory(afterReceiveMessagePostProcessor);
factory.setConcurrentConsumers(5);
factory.setPrefetchCount(10);
//这里可以获取本地的host 这样就可以在island和mq监控都能看到
factory.setConsumerTagStrategy(queue -> queue + "_" + IPUtils.getHostName() + "_" + UUIDUtils.genKey());
configurer.configure(factory, connectionFactory);
return factory;
}
@NoArgsConstructor
@AllArgsConstructor
public class LoggedSimpleRabbitListenerContainerFactory extends SimpleRabbitListenerContainerFactory {
private AfterReceiveMessagePostProcessor afterReceiveMessagePostProcessor;
@Override
protected void initializeContainer(SimpleMessageListenerContainer instance,
RabbitListenerEndpoint endpoint) {
super.initializeContainer(instance, endpoint);
instance.addAfterReceivePostProcessors(afterReceiveMessagePostProcessor);
}
}
public class AfterReceiveMessagePostProcessor implements MessagePostProcessor {
private static final Marker RABBITMQ_TRACE_LOG = MarkerManager.getMarker("rabbitMQTraceLog");
/**
* 消费消息记录日志
*/
@Override
public Message postProcessMessage(Message message) {
//用于进行日志追踪
MDC.put(Constants.EXCHANGE, message.getMessageProperties().getReceivedExchange());
MDC.put(Constants.ROUTINGKEY, message.getMessageProperties().getReceivedRoutingKey());
MDC.put(Constants.QUEUE, message.getMessageProperties().getConsumerQueue());
MDC.put(Constants.MESSAGEID, message.getMessageProperties().getMessageId());
MDC.put(Constants.APPLICATION_NAME, message.getMessageProperties().getAppId());
RabbitMQLogBO rabbitMQLogBO = LogConverter.messageToLog(message, Constants.RECEIVE);
rabbitMQLogBO.setLogInfo("RabbitMQ - after receive message");
log.info(RABBITMQ_TRACE_LOG, JSON.toJSONString(rabbitMQLogBO));
return message;
}
}
拦截器拦截Listener
/**
* 消息消费拦截器
*/
@Aspect
@Log4j2
@Component
public class ReceiveMessageAop {
private static final Marker RABBITMQ_TRACE_LOG = MarkerManager.getMarker("rabbitMQTraceLog");
/**
* 拦截rabbitListener 注解
*/
@Pointcut("@annotation(rabbitListener)")
public void rabbitListenerPointcut(RabbitListener rabbitListener) {
}
/**
* 校验消息是否消费成功
*/
@Around("rabbitListenerPointcut(rabbitListener)")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint, RabbitListener rabbitListener) throws Throwable {
String exchange = MDC.get(Constants.EXCHANGE);
String routingKey = MDC.get(Constants.ROUTINGKEY);
String queue = MDC.get(Constants.QUEUE);
String messageID = MDC.get(Constants.MESSAGEID);
String applicationName = MDC.get(Constants.APPLICATION_NAME);
Object param = null;
//拿到发送的消息体 如果是有Payload注解 取payload上的 没有取第一个
//拿到所有的参数注解
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Annotation[][] parameterAnnotations = signature.getMethod().getParameterAnnotations();
//拿到所有的参数
Object[] args = proceedingJoinPoint.getArgs();
for (Annotation[] parameterAnnotation : parameterAnnotations) {
int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
for (Annotation annotation : parameterAnnotation) {
if (annotation instanceof Payload) {
Object paramValue = args[paramIndex];
param = paramValue;
}
}
}
//如果参数里包含 message 类型的取 message
for (Object arg : args) {
if (arg instanceof Message) {
param = ((Message) arg).getBody();
}
}
//如果还没有取参数第一个
if (param == null) {
param = args.length > 0 ? args[0] : "";
}
RabbitMQLogBO rabbitMQLogBO = LogConverter.toLog(exchange, routingKey, queue, messageID, applicationName, param.toString(), null, Constants.CONSUME);
rabbitMQLogBO.setLogInfo("RabbitMQ - start consume message");
log.info(RABBITMQ_TRACE_LOG, JSON.toJSONString(rabbitMQLogBO));
try {
Object obj = proceedingJoinPoint.proceed();
rabbitMQLogBO = LogConverter.toLog(exchange, routingKey, queue, messageID, applicationName, param.toString(), null, Constants.SUCCESS);
rabbitMQLogBO.setLogInfo("RabbitMQ - consume message success");
log.info(RABBITMQ_TRACE_LOG, JSON.toJSONString(rabbitMQLogBO));
return obj;
} catch (Exception ex) {
rabbitMQLogBO = LogConverter.toLog(exchange, routingKey, queue, messageID, applicationName, param.toString(), ex.toString(), Constants.ERROR);
rabbitMQLogBO.setLogInfo("RabbitMQ - consume message error");
log.info(RABBITMQ_TRACE_LOG, JSON.toJSONString(rabbitMQLogBO));
} finally {
MDC.remove(Constants.EXCHANGE);
MDC.remove(Constants.ROUTINGKEY);
MDC.remove(Constants.QUEUE);
MDC.remove(Constants.MESSAGEID);
MDC.remove(Constants.APPLICATION_NAME);
}
return null;
}
}
二、设置生产者拦截器
/**
* 设置下发送者拦截器
*/
@Bean(name = "rabbitTemplate")
@Primary
public RabbitTemplate rabbitTemplate(ConnectionFactory hjdMqConnectionFactory, BeforeSendReplyPostProcessor beforeSendReplyPostProcessor) {
LoggedRabbitTemplate loggedRabbitTemplate = new LoggedRabbitTemplate(connectionFactory, beforeSendReplyPostProcessor);
hjdMqRabbitTemplate.setReturnCallback(returnCallBackListener);
hjdMqRabbitTemplate.setMandatory(true);
hjdMqRabbitTemplate.setBeforePublishPostProcessors();
hjdMqRabbitTemplate.setConfirmCallback(confirmCallBackListener);
return hjdMqRabbitTemplate;
}
/**
* 失败后return回调
* 方便排查MQ发送成功或者失败
*/
@Service("returnCallBackListener")
@Slf4j
public class ReturnCallBackListener implements RabbitTemplate.ReturnCallback {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.error(String.format("mq send return error %s %s %s %s %s", replyCode, replyText, exchange, routingKey, new String(message.getBody())));
}
}
@Service("confirmCallBackListener")
@Slf4j
public class ConfirmCallBackListener implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (!ack) {
log.error(String.format("mq send confirm error %s %s", cause, JsonUtils.toJSONString(correlationData)));
}
}
}
/**
* 拦截日志的RabbitTemplate配置类
*/
public class LoggedRabbitTemplate extends RabbitTemplate {
/**
* 日志 LoggedRabbitTemplate 构造方法
*/
public LoggedRabbitTemplate(ConnectionFactory connectionFactory, BeforeSendReplyPostProcessor beforeSendReplyPostProcessor) {
super(connectionFactory);
addBeforePublishPostProcessors(beforeSendReplyPostProcessor);
}
/**
* 由于生产者 messageProperties没有记录 Exchange RoutingKey 我们这里重新设置下
*/
@Override
public void doSend(Channel channel, String exchangeArg, String routingKeyArg, Message message,
boolean mandatory, @Nullable CorrelationData correlationData) throws IOException {
message.getMessageProperties().setReceivedExchange(exchangeArg);
message.getMessageProperties().setReceivedRoutingKey(routingKeyArg);
CorrelationData data = correlationData;
//如果correlationData没有new一个
if (correlationData == null) {
data = new CorrelationData();
}
super.doSend(channel, exchangeArg, routingKeyArg, message, mandatory, data);
}
}