【问题标题】:SQS Listener @Headers getting body content instead of Message AttributesSQS 侦听器 @Headers 获取正文内容而不是消息属性
【发布时间】:2018-08-07 17:19:18
【问题描述】:

我正在使用 Spring Cloud SQS 消息传递来监听指定的队列。因此使用@SqsListener 注释如下:

    @SqsListener(value = "${QUEUE}", deletionPolicy = SqsMessageDeletionPolicy.ALWAYS )
    public void receive(@Headers Map<String, String> header, @Payload String message)  {
        try {
            logger.logInfo("Message payload is: "+message);
            logger.logInfo("Header from SQS is: "+header);

            if(<Some condition>){
                //Dequeue the message once message is processed successfully
                awsSQSAsync.deleteMessage(header.get(LOOKUP_DESTINATION), header.get(RECEIPT_HANDLE));
            }else{
                logger.logInfo("Message with header: " + header + " FAILED to process");
                logger.logError(FLEX_TH_SQS001);
            }
        } catch (Exception e) {
            logger.logError(FLEX_TH_SQS001, e);
        }       
    }

我能够成功连接指定队列并阅读消息。在发送消息之前,我将消息属性设置为“Key1”=“Value1”以及 aws 控制台中的消息。以下是邮件正文:

{
"service": "ecsservice"
}

我期望“标头”接收所有消息属性的映射以及一个映射,即 Key1 和 Value1。但我收到的是: {service=ecsservice} 作为填充地图。

这意味着消息的负载/正文将作为标头的一部分出现,尽管正文是正确的。

我想知道由于 @Header 标头没有获得正确的消息属性而导致我犯了什么错误。

寻求专家意见。

-PC

【问题讨论】:

    标签: spring-boot spring-cloud amazon-sqs


    【解决方案1】:

    我在我的一个春季项目中遇到了同样的问题。 我的问题是,QueueMessageHandlerFactory 的 SQS 配置与设置setArgumentResolvers

    默认情况下,spring 中的第一个参数解析器是PayloadArgumentResolver。 具有以下行为

    @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return (parameter.hasParameterAnnotation(Payload.class) || this.useDefaultResolution);
        }
    

    这里,this.useDefaultResolution 默认设置为true——这意味着任何参数都可以转换为有效负载。

    Spring 会尝试将您的方法实际参数与其中一个解析器匹配(首先是 PayloadArgumentResolver) - 实际上它会尝试将所有参数转换为 Payload

    来自 Spring 的源代码:

    @Nullable
        private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
            HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
            if (result == null) {
                for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
                    if (resolver.supportsParameter(parameter)) {
                        result = resolver;
                        this.argumentResolverCache.put(parameter, result);
                        break;
                    }
                }
            }
            return result;
        }
    

    我是如何解决这个问题的,

    Spring 解析器的覆盖默认行为

    factory.setArgumentResolvers(
                listOf(
                    new PayloadArgumentResolver(converter, null, false),
                    new HeaderMethodArgumentResolver(null, null)
                )
            )
    

    在我设置的地方,默认标志为 false,只有在参数上有注释时,spring才会尝试转换为有效负载。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      除了@SqsListener,还需要在方法中添加@MessageMapping。此注解将有助于解析方法参数。

      【讨论】:

        【解决方案3】:

        我在一个相当大的代码库中遇到了这个问题。事实证明,一个 HandlerMethodArgumentResolver 被添加到解析器列表中,这些解析器基本上用于将消息解析为参数。在我的例子中,它是 PayloadArgumentResolver,它通常总是将参数解析为有效负载,而不管注释如何。默认情况下,它似乎应该排在列表的最后,但由于我不知道的代码,它最终被添加到了前面。

        无论如何,如果您不确定,请查看您的代码,看看您是否正在对 spring 的 QueueMessageHandler 或 HandlerMethodArgumentResolver 做任何事情。

        它帮助我使用调试器并查看 HandlerMethodArgumentResolver.resolveArgument 方法以开始跟踪发生的情况。

        附:我认为您的 @SqsListener 代码看起来不错,只是我认为 @Headers 应该在技术上解析为 " 的 Map,但我不确定这会导致您看到的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-03
          • 1970-01-01
          • 2021-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-10
          相关资源
          最近更新 更多