Spring Boot集成Localstack SQS遇无效安全令牌错误求助
问题描述
我正在开发一个基于Spring Boot 2.7.9的Kotlin应用(运行于Windows平台),用于记录SQS队列消息。启动应用时触发无效安全令牌错误,但通过Docker Compose启动Localstack后,可使用AWS CLI正常创建主题、队列、订阅,也能发送接收消息。期望实现向SQS发消息时应用记录消息,同时尝试用Test Container搭建测试环境,不清楚是Docker Compose还是Spring Boot配置有误,请求排查问题。
错误信息
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMessageListenerContainer' defined in class path resource [org/springframework/cloud/aws/messaging/config/annotation/SqsConfiguration.class]: Invocation of init method failed; nested exception is com.amazonaws.services.sqs.model.AmazonSQSException: The security token included in the request is invalid. (Service: AmazonSQS; Status Code: 403; Error Code: InvalidClientTokenId; Request ID: 4cb154fc-3a61-58ca-aeea-086c2e52e235; Proxy: null) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.25.jar:5.3.25] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.25.jar:5.3.25] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.25.jar:5.3.25] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.9.jar:2.7.9] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.9.jar:2.7.9] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.9.jar:2.7.9] at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.9.jar:2.7.9] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.7.9.jar:2.7.9] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.7.9.jar:2.7.9] at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:20) ~[main/:na]
问题排查与解决
核心问题定位
CLI能正常访问Localstack但应用报错,说明问题出在Spring Boot的AWS客户端配置:
- 未指定Localstack端点:当前配置的AmazonSQSAsync客户端默认请求AWS官方服务,而非本地Localstack,官方服务不认可dummy凭证导致验证失败
- 客户端实例未被Spring管理:
amazonSQSAsync()方法未加@Bean注解,Spring Cloud AWS的自动配置组件可能未使用自定义客户端
修复步骤
1. 修改SQS配置类
添加Localstack端点配置,并修正Bean声明:
package com.example.demo import com.amazonaws.auth.AWSCredentials import com.amazonaws.auth.AWSStaticCredentialsProvider import com.amazonaws.auth.BasicAWSCredentials import com.amazonaws.client.builder.AwsClientBuilder import com.amazonaws.regions.Regions import com.amazonaws.services.sqs.AmazonSQSAsync import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.cloud.aws.messaging.config.SimpleMessageListenerContainerFactory import org.springframework.cloud.aws.messaging.config.annotation.EnableSqs import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import javax.annotation.PostConstruct @Configuration @EnableSqs class SqsConfiguration { private val logger: Logger = LoggerFactory.getLogger(SqsConfiguration::class.java) @Bean fun credentials(): AWSCredentials { return BasicAWSCredentials("dummy", "dummy") } @Bean // 关键:让Spring管理此客户端实例 fun amazonSQSAsync(): AmazonSQSAsync { return AmazonSQSAsyncClientBuilder.standard() .withEndpointConfiguration( AwsClientBuilder.EndpointConfiguration( "http://localhost:4566", // 指定Localstack端点 Regions.US_EAST_1.name ) ) .withCredentials(AWSStaticCredentialsProvider(credentials())) .build() } @Bean fun queueMessagingTemplate(): QueueMessagingTemplate { return QueueMessagingTemplate(amazonSQSAsync()) } @Bean fun simpleMessageListenerContainerFactory(): SimpleMessageListenerContainerFactory { val msgListenerContainerFactory = SimpleMessageListenerContainerFactory() msgListenerContainerFactory.setAmazonSqs(amazonSQSAsync()) return msgListenerContainerFactory } @PostConstruct fun init() { logger.info("SqsConfiguration created") } }
2. 可选:用配置文件灵活配置端点
在src/main/resources/application.yml中添加配置,避免硬编码:
cloud: aws: region: static: us-east-1 stack: auto: false sqs: endpoint: http://localhost:4566 credentials: access-key: dummy secret-key: dummy
此时可简化配置类,仅保留@EnableSqs和必要Bean。
3. 验证消费者队列名称
确保@SqsListener中的队列名称与CLI创建的一致,或使用完整URL:
@SqsListener("http://localhost:4566/000000000000/test-queue")
4. Test Container集成配置
添加Testcontainers依赖到build.gradle:
testImplementation("org.testcontainers:localstack:1.17.6") testImplementation("org.testcontainers:junit-jupiter:1.17.6")
编写测试类:
package com.example.demo import org.junit.jupiter.api.Test import org.springframework.boot.test.context.SpringBootTest import org.testcontainers.containers.localstack.LocalStackContainer import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName @Testcontainers @SpringBootTest(properties = [ "cloud.aws.sqs.endpoint=\${localstack.sqs.endpoint}", "cloud.aws.credentials.access-key=dummy", "cloud.aws.credentials.secret-key=dummy", "cloud.aws.region.static=us-east-1" ]) class SqsIntegrationTest { companion object { @Container val localstack = LocalStackContainer(DockerImageName.parse("localstack/localstack:latest")) .withServices(LocalStackContainer.Service.SQS, LocalStackContainer.Service.SNS) init { System.setProperty("localstack.sqs.endpoint", localstack.getEndpointOverride(LocalStackContainer.Service.SQS).toString()) } } @Test fun testSqsMessageReceiving() { // 编写测试逻辑:发送消息并验证消费者接收 } }
验证修复
- 重启Localstack和Spring Boot应用
- 使用CLI发送消息到SNS主题,检查应用日志是否输出
Received message: Hello World
内容的提问来源于stack exchange,提问作者ZiimyX
相关产品推荐
相关产品推荐

