简体   繁体   English

使用 Spring Boot 侦听消息队列 SQS 不适用于标准配置

[英]Listen message queue SQS with Spring Boot not works with standard config

I'm unable to make works queue listener with Spring Boot and SQS (the message is sent and appear in SQS ui)我无法使用 Spring Boot 和 SQS 制作工作队列侦听器(消息已发送并出现在 SQS ui 中)

The @MessageMapping or @SqsListener not works @MessageMapping@SqsListener不起作用

Java: 11爪哇:11
Spring Boot: 2.1.7弹簧靴:2.1.7
Dependencie: spring-cloud-aws-messaging依赖:spring-cloud-aws-messaging

This is my config这是我的配置

@Configuration
@EnableSqs
public class SqsConfig {

    @Value("#{'${env.name:DEV}'}")
    private String envName;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Value("${cloud.aws.credentials.access-key}")
    private String awsAccessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String awsSecretKey;

    @Bean
    public Headers headers() {
        return new Headers();
    }

    @Bean
    public MessageQueue queueMessagingSqs(Headers headers,
                                          QueueMessagingTemplate queueMessagingTemplate) {
        Sqs queue = new Sqs();
        queue.setQueueMessagingTemplate(queueMessagingTemplate);
        queue.setHeaders(headers);
        return queue;
    }

    private ResourceIdResolver getResourceIdResolver() {
        return queueName -> envName + "-" + queueName;
    }

    @Bean
    public DestinationResolver destinationResolver(AmazonSQSAsync amazonSQSAsync) {
        DynamicQueueUrlDestinationResolver destinationResolver = new DynamicQueueUrlDestinationResolver(
                amazonSQSAsync,
                getResourceIdResolver());
        destinationResolver.setAutoCreate(true);
        return destinationResolver;
    }

    @Bean
    public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync,
                                                         DestinationResolver destinationResolver) {
        return new QueueMessagingTemplate(amazonSQSAsync, destinationResolver, null);
    }

    @Bean
    public QueueMessageHandlerFactory queueMessageHandlerFactory() {
        QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
        MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
        messageConverter.setStrictContentTypeMatch(false);
        factory.setArgumentResolvers(Collections.singletonList(new PayloadArgumentResolver(messageConverter)));
        return factory;
    }

    @Bean
    public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSqs) {
        SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
        factory.setAmazonSqs(amazonSqs);
        factory.setMaxNumberOfMessages(10);
        factory.setWaitTimeOut(2);
        return factory;
    }

}

I notice also that org.springframework.cloud.aws.messaging.config.SimpleMessageListenerContainerFactory and org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration run on startup我还注意到org.springframework.cloud.aws.messaging.config.SimpleMessageListenerContainerFactoryorg.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration在启动时运行

And my test还有我的测试

@RunWith(SpringJUnit4ClassRunner.class)
public class ListenTest {

    @Autowired
    private MessageQueue queue;

    private final String queueName = "test-queue-receive";

    private String result = null;

    @Test
    public void test_listen() {
        // given
        String data = "abc";

        // when
        queue.send(queueName, data).join();

        // then
        Awaitility.await()
                .atMost(10, TimeUnit.SECONDS)
                .until(() -> Objects.nonNull(result));

        Assertions.assertThat(result).equals(data);
    }

    @MessageMapping(value = queueName)
    public void receive(String data) {
        this.result = data;
    }
}

Do you think something is wrong ?你觉得有什么不对吗?

I create a repo for exemple : ( https://github.com/mmaryo/java-sqs-test )我为 example 创建了一个 repo :( https://github.com/mmaryo/java-sqs-test
In test folder, change aws credentials in 'application.yml'在测试文件夹中,更改“application.yml”中的 aws 凭据
Then run tests然后运行测试

I had the same issue when using the spring-cloud-aws-messaging package, but then I used the queue URL in the @SqsListener annotation instead of the queue name and it worked.我在使用 spring-cloud-aws-messaging 包时遇到了同样的问题,但后来我在 @SqsListener 注释中使用了队列 URL 而不是队列名称,并且它起作用了。

@SqsListener(value = { "https://full-queue-URL" }, deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void receive(String message) {
     // do something
}

It seems you can use the queue name when using the spring-cloud-starter-aws-messaging package.使用 spring-cloud-starter-aws-messaging 包时,您似乎可以使用队列名称。 I believe there is some configuration that allows usage of the queue name instead of URL if you don't want to use the starter package.如果您不想使用 starter 包,我相信有一些配置允许使用队列名称而不是 URL。

EDIT: I noticed the region was being defaulted to us-west-2 despite me listing us-east-1 in my properties file.编辑:尽管我在我的属性文件中列出了 us-east-1,但我注意到该区域被默认为 us-west-2。 Then I created a RegionProvider bean and set the region to us-east-1 in there and now when I use the queue name in the @SqsMessaging it is found and correctly resolved to the URL in the framework code.然后我创建了一个 RegionProvider bean 并将区域设置为 us-east-1,现在当我在 @SqsMessaging 中使用队列名称时,它被找到并正确解析为框架代码中的 URL。

you'll need to leverage the @Primary annotation, this is what worked for me:您需要利用 @Primary 注释,这对我有用:

@Autowired(required = false)
private AWSCredentialsProvider awsCredentialsProvider;

@Autowired
private AppConfig appConfig;

@Bean
public QueueMessagingTemplate getQueueMessagingTemplate() {
    return new QueueMessagingTemplate(sqsClient());
}

@Primary
@Bean
public AmazonSQSAsync sqsClient() {
    AmazonSQSAsyncClientBuilder builder = AmazonSQSAsyncClientBuilder.standard();

    if (this.awsCredentialsProvider != null) {
        builder.withCredentials(this.awsCredentialsProvider);
    }

    if (appConfig.getSqsRegion() != null) {
        builder.withRegion(appConfig.getSqsRegion());
    } else {
        builder.withRegion(Regions.DEFAULT_REGION);
    }

    return builder.build();
}

build.gradle needs these deps: build.gradle 需要这些 deps:

implementation("org.springframework.cloud:spring-cloud-starter-aws:2.2.0.RELEASE")
implementation("org.springframework.cloud:spring-cloud-aws-messaging:2.2.0.RELEASE")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM