RabbitMQ学习笔记:Springboot amqp之 spring_listener_return_correlation、 spring_returned_message_correlati

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

 

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

1.引入springboot amqp依赖
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-amqp</artifactId>
            </dependency>

启用消息未成功发送到队列时强制退回及开启回调功能:

    spring.rabbitmq.publisher-returns=true
    spring.rabbitmq.template.mandatory=true
2.发送消息到RabbitMQ消息服务器我们可以看到headers有两个属性

这两个属性分别代表什么意思呢?我们看下org.springframework.amqp.rabbit.connection.PublisherCallbackChannel接口:

    public interface PublisherCallbackChannel extends Channel {
    
    	/**
    	 * Header used to determine which listener to invoke for a returned message.
    	 */
    	String RETURN_LISTENER_CORRELATION_KEY = "spring_listener_return_correlation";
    
    	/**
    	 * Header used to locate a pending confirm to which to attach a returned message.
    	 */
    	String RETURNED_MESSAGE_CORRELATION_KEY = "spring_returned_message_correlation";
    	}
  • spring_listener_return_correlation:该属性是用来确定消息被退回时调用哪个监听器
  • spring_returned_message_correlation:该属性是指退回待确认消息的唯一标识
3.spring_returned_message_correlation在哪里设置,又有什么作用?

发送消息时有一个退回消息相关数据org.springframework.amqp.rabbit.connection.CorrelationData类,这个header属性对应相关数据类的Id属性

        private final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.err.println("return exchange: " + exchange + ", routingKey: "
                        + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText+",MessageId:"+message.getMessageProperties().getMessageId());
            }
        };
    
    
    public void sendMsg(String exchange, String routingKey, String message, Map<String, Object> properties){
            org.springframework.messaging.Message msg = org.springframework.messaging.support.MessageBuilder.withPayload(message).build();
            /**
             * 设置生产者消息publish-confirm回调函数
             */
            this.rabbitTemplate.setConfirmCallback(confirmCallback);
            /**
             * 设置消息退回回调函数
             */
            this.rabbitTemplate.setReturnCallback(returnCallback);
            /**
             * 将消息主题和属性封装在Message类中
             */
            Message returnedMessage = MessageBuilder.withBody(message.getBytes()).build();
            /**
             * 相关数据
             */
            CorrelationData correlationData = new CorrelationData();
            /**
             * 消息ID,全局唯一
             */
            correlationData.setId(msg.getHeaders().getId().toString());
    
            /**
             * 设置此相关数据的返回消息
             */
            correlationData.setReturnedMessage(returnedMessage);
            /**
             * 如果msg是org.springframework.amqp.core.Message对象的实例,则直接返回,否则转化为Message对象
             */
            this.rabbitTemplate.convertAndSend(exchange, routingKey, msg, new MessagePostProcessor() {
                /**
                 * 消息后置处理器,消息在转换成Message对象之后调用,可以用来修改消息中的属性、header
                 */
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
    				...
                    return message;
                }
            }, correlationData);
        }

对应上面代码的correlationData.setId(msg.getHeaders().getId().toString());方法

这个消息ID主要是用来在发送端记录发送了哪些消息,哪些消息已经成功确认,哪些消息发送失败,需要进一步的处理,如重试等等;

4.spring_listener_return_correlation属性是在哪里设置的?又是起什么作用?

在org.springframework.amqp.rabbit.core.RabbitTemplate类中有如下方法:

    //随机生成
    private final String uuid = UUID.randomUUID().toString();
    
    public void doSend(Channel channel, String exchangeArg, String routingKeyArg, Message message, // NOSONAR complexity
    			boolean mandatory, @Nullable CorrelationData correlationData)
    					throws Exception { // NOSONAR TODO: change to IOException in 2.2.
    
    		...
    
    		Message messageToUse = message;
    		MessageProperties messageProperties = messageToUse.getMessageProperties();
    		if (mandatory) {
    //设置spring_listener_return_correlation属性值	
                messageProperties.getHeaders().put(PublisherCallbackChannel.RETURN_LISTENER_CORRELATION_KEY, this.uuid);
    		}
    		if (this.beforePublishPostProcessors != null) {
    			for (MessagePostProcessor processor : this.beforePublishPostProcessors) {
    				messageToUse = processor.postProcessMessage(messageToUse, correlationData);
    			}
    		}
        //在此方法中会从退回消息相关数据类中取spring_returned_message_correlation设置到Message对象
    		setupConfirm(channel, messageToUse, correlationData);
    		if (this.userIdExpression != null && messageProperties.getUserId() == null) {
    			String userId = this.userIdExpression.getValue(this.evaluationContext, messageToUse, String.class);
    			if (userId != null) {
    				messageProperties.setUserId(userId);
    			}
    		}
    		sendToRabbit(channel, exch, rKey, mandatory, messageToUse);
    		// Check if commit needed
    		if (isChannelLocallyTransacted(channel)) {
    			// Transacted channel created by this template -> commit.
    			RabbitUtils.commitIfNecessary(channel);
    		}
    	}

spring_returned_message_correlation属性设置

    	private void setupConfirm(Channel channel, Message message, @Nullable CorrelationData correlationDataArg) {
    		if ((this.publisherConfirms || this.confirmCallback != null) && channel instanceof PublisherCallbackChannel) {
    
    			PublisherCallbackChannel publisherCallbackChannel = (PublisherCallbackChannel) channel;
    			CorrelationData correlationData = this.correlationDataPostProcessor != null
    					? this.correlationDataPostProcessor.postProcess(message, correlationDataArg)
    					: correlationDataArg;
    			long nextPublishSeqNo = channel.getNextPublishSeqNo();
    			message.getMessageProperties().setPublishSequenceNumber(nextPublishSeqNo);
    			publisherCallbackChannel.addPendingConfirm(this, nextPublishSeqNo,
    					new PendingConfirm(correlationData, System.currentTimeMillis()));
    			if (correlationData != null && StringUtils.hasText(correlationData.getId())) {
    				message.getMessageProperties().setHeader(PublisherCallbackChannel.RETURNED_MESSAGE_CORRELATION_KEY,
    						correlationData.getId());
    			}
    		}
    		else if (channel instanceof ChannelProxy && ((ChannelProxy) channel).isConfirmSelected()) {
    			long nextPublishSeqNo = channel.getNextPublishSeqNo();
    			message.getMessageProperties().setPublishSequenceNumber(nextPublishSeqNo);
    		}
    	}

spring_listener_return_correlation的属性作用是确认调用哪个监听器,即消息退回处理回调方法。

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值