当我尝试使用SQS消息时,我看到以下异常:
org.springframework.messaging.converter.MessageConversionException:
Cannot convert from [java.lang.String] to [com.example.demo.Foo] for GenericMessage [payload={}, headers={LogicalResourceId=my-queue, ApproximateReceiveCount=1, SentTimestamp=1529021258825, ReceiptHandle=xxxx, Visibility=org.springframework.cloud.aws.messaging.listener.QueueMessageVisibility@47ce6922, SenderId=xxxx, lookupDestination=my-queue, ApproximateFirstReceiveTimestamp=1529021264456, MessageId=xxxx}]
at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:144)
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:116)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:137)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:109)
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:515)
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:473)
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:409)
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.executeMessage(SimpleMessageListenerContainer.java:205)
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.java:342)
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.java:397)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Spring Boot代码如下:
@Configuration
@EnableSqs
public class AmazonSqsConfiguration {
@Bean
public AmazonSQS amazonSQSAsync() {
return AmazonSQSAsyncClientBuilder.standard()
.withRegion(Regions.US_WEST_2)
.build();
}
}
@Service
public class MyService {
// Throws MessageConversionException
@SqsListener("my-queue")
public void listen(Foo payload) {
}
// Works fine
@SqsListener("my-queue")
public void listen(String payload) {
}
}
我正在使用org.springframework.cloud:spring-cloud-aws-messaging:2.0.0.RC2
我的类路径上有Jackson 2库,因此PayloadArgumentResolver
正在尝试使用MappingJackson2MessageConverter
反序列化我的消息有效负载。但是,由于缺少contentType
标头的SQS消息,并且strictContentTypeMatch
设置为true,canConvertFrom
将返回false。
我看不出如何为SQS消息设置contentType
标头 - 我错过了什么?
Spring Cloud QueueMessageHandler
是否应将strictContentTypeMatch
设置为true?
答案 0 :(得分:6)
遇到同样的问题,我会根据是谁生成消息来回答以下两种方式之一的问题
是的,可以在消息上设置contentType
,并且如果您控制正在生成的消息,则这是首选。在AWS控制台中,当您手动发送消息时,会有一个“消息属性”选项卡。您将添加一个名称为contentType
且值为application/json
的属性。 AWS SDK调用应允许您从应用程序代码执行相同的操作。
对于AWS生成的没有内容指定内容类型的消息,例如S3事件,实际上您确实需要将strictContentMatch
设置为false。在此处记录:
http://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.0.0.RELEASE/multi/multi__messaging.html#_consuming_aws_event_messages_with_amazon_sqs
文档令人困惑,因为它说“没有mime类型的标题”,但是标题的实际名称是contentType
,就像您发现的那样。
答案 1 :(得分:0)
在“发送”和“监听”方法中都具有一致的转换器:
/** Provides a deserialization template for incoming SQS messages */
@Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory(MessageConverter messageConverter) {
var factory = new QueueMessageHandlerFactory();
factory.setArgumentResolvers(singletonList(new PayloadArgumentResolver(messageConverter)));
return factory;
}
/** Provides a serialization template for outgoing SQS messages */
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync, MessageConverter messageConverter) {
return new QueueMessagingTemplate(amazonSQSAsync, (ResourceIdResolver) null, messageConverter);
}
/** Provides JSON converter for SQS messages */
@Bean
protected MessageConverter messageConverter(ObjectMapper objectMapper) {
var converter = new MappingJackson2MessageConverter();
converter.setObjectMapper(objectMapper);
// Serialization support:
converter.setSerializedPayloadClass(String.class);
// Deserialization support: (suppress "contentType=application/json" header requirement)
converter.setStrictContentTypeMatch(false);
return converter;
}
在原始接受的答案中查看详细信息。归功于@wrschneider。
注意:上面的示例注入并设置了ObjectMapper。这是可选的,以确保HTTP REST控制器的一致性。
进口:
import static java.util.Collections.singletonList;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.aws.core.env.ResourceIdResolver;
import org.springframework.cloud.aws.messaging.config.QueueMessageHandlerFactory;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver;
用法:
@SqsListener("my-queue")
public void listen(Foo payload) {
}
public void send(Foo dto) {
queueMessagingTemplate.convertAndSend(url, dto);
}