我正在创建一个 spring boot 应用程序来在 SQS 队列上记录消息,启动应用程序时出现安全令牌错误。我正在使用 spring boot 版本 2.7.9,应用程序是用 kotlin 编写的,运行在 windows 平台上。我有一个 docker compose 文件来启动 Localstack 并可以创建主题、队列和订阅。我的期望是,当我向 bash shell 中的 sqs 队列发送消息时,应用程序会记录该消息。我不知道 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]
码头文件:
version: '3.0'
services:
localstack:
image: localstack/localstack:latest
environment:
- SERVICES=sqs,sns
- AWS_DEFAULT_REGION=us-east-1
- EDGE_PORT=4566
ports:
- '4566-4597:4566-4597'
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
build.gradle
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.7.9"
id("io.spring.dependency-management") version "1.0.15.RELEASE"
kotlin("jvm") version "1.6.21"
kotlin("plugin.spring") version "1.6.21"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE")
implementation("org.springframework.cloud:spring-cloud-starter-aws-messaging:2.2.6.RELEASE")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
Spring boot 配置文件,我创建了一个 aws_access_key_id 和 aws_secret_access_key 设置为 'dummy' 的 AWS 测试配置文件
package com.example.demo
import com.amazonaws.auth.AWSCredentials
import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.auth.BasicAWSCredentials
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
fun queueMessagingTemplate(): QueueMessagingTemplate? {
return QueueMessagingTemplate(amazonSQSAsync())
}
fun amazonSQSAsync(): AmazonSQSAsync {
return AmazonSQSAsyncClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.withCredentials(AWSStaticCredentialsProvider(credentials()))
.build()
}
@Bean
fun simpleMessageListenerContainerFactory(): SimpleMessageListenerContainerFactory? {
val msgListenerContainerFactory = SimpleMessageListenerContainerFactory()
msgListenerContainerFactory.setAmazonSqs(amazonSQSAsync())
return msgListenerContainerFactory
}
@PostConstruct
fun init() {
logger.info("SqsConfiguration created")
}
}
消费类是:
package com.example.demo
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct
@Component
class Consumer {
private val logger: Logger = LoggerFactory.getLogger(Consumer::class.java)
@SqsListener("test-queue")
fun receiveMessage(message: String) {
logger.info("Received message: {}", message)
}
@PostConstruct
fun init() {
logger.info("Consumer created")
}
}
最后boot strap类是:
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication(
exclude =
[
org.springframework.cloud.aws.autoconfigure.context.ContextInstanceDataAutoConfiguration::class,
org.springframework.cloud.aws.autoconfigure.context.ContextStackAutoConfiguration::class,
org.springframework.cloud.aws.autoconfigure.context.ContextRegionProviderAutoConfiguration::class
]
)
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}