Java 将SqsListener与SNS和SQS一起使用

Java 将SqsListener与SNS和SQS一起使用,java,spring,amazon-web-services,spring-cloud,spring-cloud-aws,Java,Spring,Amazon Web Services,Spring Cloud,Spring Cloud Aws,我使用的是从AWS的简单队列服务(SQS)接收AWS SNS HTTP通知 以下是侦听器的代码: @SqsListener(value = "my-queue", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS) public void handle(final MyObject obj) throws Exception { // ... } 上面链接的文档只是关于向队列发送和读取普通序列化对象的,我认为接收SNS消息应该是开箱即用的

我使用的是从AWS的简单队列服务(SQS)接收AWS SNS HTTP通知

以下是侦听器的代码:

@SqsListener(value = "my-queue", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void handle(final MyObject obj) throws Exception {
// ...
}
上面链接的文档只是关于向队列发送和读取普通序列化对象的,我认为接收SNS消息应该是开箱即用的。但我最终收到了转换错误:

10:45:51.480[simpleMessageListenerContainer-2]错误 o、 s.c.a.m.l.SimpleMessageListenerContainer-遇到异常 在处理消息时。 org.springframework.MessagingException:异常 调用处理程序方法时发生;嵌套异常是 org.springframework.messaging.converter.MessageConversionException:否 找到要转换为com.myproject.model.MyObject类的转换器, message=GenericMessage


我还尝试创建一个类似于上面链接的预期SNS Json格式的包装器对象,但我一直得到相同的异常。唯一有效的类型是签名中的字符串。SNS不应该自动转换吗?

是的,应该。事实上确实如此

为了在反序列化时调用正确的
HandlerMethodArgumentResolver
(在本例中为
NotificationMessageArgumentResolver
),然后调用正确的转换器
NotificationRequestConverter
,只需将注释
org.springframework.cloud.aws.messaging.config.annotation.NotificationMessage
添加到方法签名中即可。例如

@SqsListener(value = "my-queue", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void handle(final @NotificationMessage MyObject obj) throws Exception {
// ...
}

通过这种方式,SNS的
消息
部分被提取并转换为
MyObject

,这在没有
@NotificationMessage
的情况下也可以工作。这样,您就不需要发送处理此注释所需的“类型”和“消息”部分

首先创建一个具有所需属性的类

public class SqsMessage {

   private String myTask;

   public SqsMessage() {
   }

   public SqsMessage(@JsonProperty("MyTask") String myTask ) {
       this.myTask = myTask ;
   }

   //Getter + Setter 
}
接下来设置侦听器

@SqsListener(value = {"MyQueue"}, deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void receiveMessage(SqsMessage payload, @Headers Map<String, Object> header) {
   logger.info("Got message with task: " + payload.getTask() 
    + " with custom attribute " + header.get("CustomAttribute").toString());
}

POJO构造函数中的
@JsonProperty(“MyTask”)
注释可以是可选的,这取决于您的spring版本以及您的属性是否与Json字符串中的名称相同。例如,如果您的属性名为
task
,Json字符串名为
{“task”:“我的任务”}

您如何能够从SQS接收字符串形式的对象?SQS只支持字符串作为消息,这不是真的吗?@jtcotton63这是真的。负载以
String
-一个JSON对象的形式出现,
@NotificationMessage
调用一个转换器,该转换器将负载转换为所需类的对象。添加到这个答案中,对我来说,简单地添加@NotificationMessage注释没有帮助,因为我用自己的ArgumentResolver覆盖了QueueMessageHandlerFactory。这对于许多人来说都是如此,因为这是定制Jackson mapper所必需的。在这种情况下,必须更改解析器:from
factory.setArgumentResolver(List.of(new PayloadArgumentResolver(jacksonMessageConverter))
工厂.setArgumentResolver(新NotificationMessageArgumentResolver(jacksonMessageConverter))的列表但问题是关于接收SNS消息,其中
类型
消息
是它的一部分,这是很久以前的事了,但据我所记得的,
消息
被映射到POJO,
类型
信息是标题的一部分。我的答案与接受的答案完全相同,但没有使用
@NotificationMessage
注释,这在我的情况下会导致其他解析问题。JSON的东西只是一种奖励。
{"MyTask":"My task"}