rabbitmq 发送消息跟踪

3 篇文章 0 订阅
1 篇文章 0 订阅

一、设置消费者拦截器

继承 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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值