SQS Listener @Headers获取正文内容而不是消息属性

时间:2018-02-27 22:47:14

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

我正在使用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"
}

我希望“header”能够接收所有消息属性的Map以及Key1和Value1。但我收到的是: {service = ecsservice}作为填充的地图。

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

我想知道由于哪个@Header标头没有获得正确的消息属性而我正在做什么错误。

寻求专家意见。

-PC

3 个答案:

答案 0 :(得分:0)

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

无论如何,如果您不确定要查看代码并查看是否正在执行有关spring的QueueMessageHandler或HandlerMethodArgumentResolver的任何操作。

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

P.S。我认为你的@SqsListener代码看起来很好,除了我认为@Headers应该在技术上解析为&lt;字符串,对象&gt;“,但我不确定这会导致您遇到的问题。

答案 1 :(得分:0)

我在一个春季项目中遇到了同样的问题。 对我来说,问题是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 :(得分:0)

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