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

Pan*_*han 6 amazon-sqs spring-boot spring-cloud

我正在使用 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);
        }       
    }
Run Code Online (Sandbox Code Playgroud)

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

{
"service": "ecsservice"
}
Run Code Online (Sandbox Code Playgroud)

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

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

我想知道我犯了什么错误,因为 @Header 标头没有获得正确的消息属性。

寻求专家建议。

-个人电脑

Gop*_*ote 7

我在一个春季项目中遇到了同样的问题。\n对我来说问题是,SQS配置与QueueMessageHandlerFactorySetting setArgumentResolvers

\n\n

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

\n\n
@Override\n    public boolean supportsParameter(MethodParameter parameter) {\n        return (parameter.hasParameterAnnotation(Payload.class) || this.useDefaultResolution);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里,this.useDefaultResolution默认设置为true\xe2\x80\x93,这意味着任何参数都可以转换为Payload。

\n\n

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

\n\n

来自 Spring 的源代码:

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

我是如何解决这个问题的

\n\n

Spring 解析器的重写默认行为

\n\n
factory.setArgumentResolvers(\n            listOf(\n                new PayloadArgumentResolver(converter, null, false),\n                new HeaderMethodArgumentResolver(null, null)\n            )\n        )\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

希望这会有所帮助。

\n