【问题标题】:Spring Cloud @SqsListener MessageConversionException: Cannot convert from [java.lang.String] for GenericMessageSpring Cloud @SqsListener MessageConversionException:无法从 [java.lang.String] 转换为 GenericMessage
【发布时间】:2018-11-24 19:59:56
【问题描述】:

我在尝试使用 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 反序列化我的消息负载。但是,由于 SQS 消息缺少 contentType 标头并且 strictContentTypeMatch 设置为 true,所以 canConvertFrom 返回 false。

https://github.com/spring-projects/spring-framework/blob/f5e8f4983f7653169f3da8a3287499fce93cadd4/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java#L237

我看不到如何为 SQS 消息设置 contentType 标头 - 我错过了什么吗?

Spring Cloud QueueMessageHandler 是否应该将 strictContentTypeMatch 设置为 true?

https://github.com/spring-cloud/spring-cloud-aws/blob/6a7c3c31709d4239131b27936de29385df414d41/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/listener/QueueMessageHandler.java#L217

【问题讨论】:

  • 你解决了这个问题吗?

标签: java spring-cloud amazon-sqs


【解决方案1】:

遇到同样的问题,我会根据谁生成消息以两种方式之一回答问题

该文档令人困惑,因为它说“没有 mime 类型的标题”,但标题的实际名称是 contentType,正如您自己发现的那样。

【讨论】:

    【解决方案2】:

    在“发送”和“收听”方法中都有一个一致的转换器:

    /** 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);
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 1970-01-01
      • 2021-05-22
      • 1970-01-01
      • 2017-06-19
      • 2017-01-31
      • 1970-01-01
      相关资源
      最近更新 更多