聞こえないJavaエンジニアが適当に書き連ねていく

つらつらとメモしたり日頃の溜まっている想いを吐き出す場所です。

LocalStack + Spring Boot でAWS SQSの開発環境を構築する際のメモ

これは何

動くようになるまでにドはまりしたのであとあと確認出来るようにメモ

前提

関係ありそうなバージョン情報は以下の通り

  • Java:11
  • Spring Boot:2.3.7
  • Spring Cloud:Hoxton.SR9
  • aws-java-sdk-core:1.11.792

AWS SDKはVersion2が出ているようだが、Spring Boot側がそれに対応したバージョンがまだリリースされていない模様。

build.gradleの定義

spring initializr でweb、aws core、aws simple queue serviceを選択している。

plugins {
    id 'org.springframework.boot' version '2.3.7.RELEASE'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

ext {
    set('springCloudVersion', "Hoxton.SR9")
}

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.cloud:spring-cloud-starter-aws'
    implementation 'org.springframework.cloud:spring-cloud-starter-aws-messaging'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

test {
    useJUnitPlatform()
}

依存関係

compileClasspathのみ記載。

compileClasspath - Compile classpath for source set 'main'.
+--- org.springframework.boot:spring-boot-starter-web -> 2.3.7.RELEASE
|    +--- org.springframework.boot:spring-boot-starter:2.3.7.RELEASE
|    |    +--- org.springframework.boot:spring-boot:2.3.7.RELEASE
|    |    |    +--- org.springframework:spring-core:5.2.12.RELEASE
|    |    |    |    \--- org.springframework:spring-jcl:5.2.12.RELEASE
|    |    |    \--- org.springframework:spring-context:5.2.12.RELEASE
|    |    |         +--- org.springframework:spring-aop:5.2.12.RELEASE
|    |    |         |    +--- org.springframework:spring-beans:5.2.12.RELEASE
|    |    |         |    |    \--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    |         |    \--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    |         +--- org.springframework:spring-beans:5.2.12.RELEASE (*)
|    |    |         +--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    |         \--- org.springframework:spring-expression:5.2.12.RELEASE
|    |    |              \--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    +--- org.springframework.boot:spring-boot-autoconfigure:2.3.7.RELEASE
|    |    |    \--- org.springframework.boot:spring-boot:2.3.7.RELEASE (*)
|    |    +--- org.springframework.boot:spring-boot-starter-logging:2.3.7.RELEASE
|    |    |    +--- ch.qos.logback:logback-classic:1.2.3
|    |    |    |    +--- ch.qos.logback:logback-core:1.2.3
|    |    |    |    \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30
|    |    |    +--- org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|    |    |    |    +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30
|    |    |    |    \--- org.apache.logging.log4j:log4j-api:2.13.3
|    |    |    \--- org.slf4j:jul-to-slf4j:1.7.30
|    |    |         \--- org.slf4j:slf4j-api:1.7.30
|    |    +--- jakarta.annotation:jakarta.annotation-api:1.3.5
|    |    +--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    \--- org.yaml:snakeyaml:1.26
|    +--- org.springframework.boot:spring-boot-starter-json:2.3.7.RELEASE
|    |    +--- org.springframework.boot:spring-boot-starter:2.3.7.RELEASE (*)
|    |    +--- org.springframework:spring-web:5.2.12.RELEASE
|    |    |    +--- org.springframework:spring-beans:5.2.12.RELEASE (*)
|    |    |    \--- org.springframework:spring-core:5.2.12.RELEASE (*)
|    |    +--- com.fasterxml.jackson.core:jackson-databind:2.11.3
|    |    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.11.3
|    |    |    \--- com.fasterxml.jackson.core:jackson-core:2.11.3
|    |    +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.3
|    |    |    +--- com.fasterxml.jackson.core:jackson-core:2.11.3
|    |    |    \--- com.fasterxml.jackson.core:jackson-databind:2.11.3 (*)
|    |    +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3
|    |    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.11.3
|    |    |    +--- com.fasterxml.jackson.core:jackson-core:2.11.3
|    |    |    \--- com.fasterxml.jackson.core:jackson-databind:2.11.3 (*)
|    |    \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.3
|    |         +--- com.fasterxml.jackson.core:jackson-core:2.11.3
|    |         \--- com.fasterxml.jackson.core:jackson-databind:2.11.3 (*)
|    +--- org.springframework.boot:spring-boot-starter-tomcat:2.3.7.RELEASE
|    |    +--- jakarta.annotation:jakarta.annotation-api:1.3.5
|    |    +--- org.apache.tomcat.embed:tomcat-embed-core:9.0.41
|    |    +--- org.glassfish:jakarta.el:3.0.3
|    |    \--- org.apache.tomcat.embed:tomcat-embed-websocket:9.0.41
|    |         \--- org.apache.tomcat.embed:tomcat-embed-core:9.0.41
|    +--- org.springframework:spring-web:5.2.12.RELEASE (*)
|    \--- org.springframework:spring-webmvc:5.2.12.RELEASE
|         +--- org.springframework:spring-aop:5.2.12.RELEASE (*)
|         +--- org.springframework:spring-beans:5.2.12.RELEASE (*)
|         +--- org.springframework:spring-context:5.2.12.RELEASE (*)
|         +--- org.springframework:spring-core:5.2.12.RELEASE (*)
|         +--- org.springframework:spring-expression:5.2.12.RELEASE (*)
|         \--- org.springframework:spring-web:5.2.12.RELEASE (*)
+--- org.springframework.cloud:spring-cloud-starter-aws -> 2.2.5.RELEASE
|    +--- org.springframework.cloud:spring-cloud-aws-context:2.2.5.RELEASE
|    |    +--- org.springframework.cloud:spring-cloud-aws-core:2.2.5.RELEASE
|    |    |    +--- org.springframework:spring-beans:5.2.8.RELEASE -> 5.2.12.RELEASE (*)
|    |    |    +--- org.springframework:spring-aop:5.2.8.RELEASE -> 5.2.12.RELEASE (*)
|    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792
|    |    |    |    +--- org.apache.httpcomponents:httpclient:4.5.9 -> 4.5.13
|    |    |    |    |    +--- org.apache.httpcomponents:httpcore:4.4.13 -> 4.4.14
|    |    |    |    |    \--- commons-codec:commons-codec:1.11 -> 1.14
|    |    |    |    +--- software.amazon.ion:ion-java:1.0.2
|    |    |    |    +--- com.fasterxml.jackson.core:jackson-databind:2.6.7.3 -> 2.11.3 (*)
|    |    |    |    +--- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.6.7 -> 2.11.3
|    |    |    |    |    +--- com.fasterxml.jackson.core:jackson-databind:2.11.3 (*)
|    |    |    |    |    \--- com.fasterxml.jackson.core:jackson-core:2.11.3
|    |    |    |    \--- joda-time:joda-time:2.8.1
|    |    |    +--- com.amazonaws:aws-java-sdk-s3:1.11.792
|    |    |    |    +--- com.amazonaws:aws-java-sdk-kms:1.11.792
|    |    |    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
|    |    |    |    |    \--- com.amazonaws:jmespath-java:1.11.792
|    |    |    |    |         \--- com.fasterxml.jackson.core:jackson-databind:2.6.7.3 -> 2.11.3 (*)
|    |    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
|    |    |    |    \--- com.amazonaws:jmespath-java:1.11.792 (*)
|    |    |    +--- com.amazonaws:aws-java-sdk-ec2:1.11.792
|    |    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
|    |    |    |    \--- com.amazonaws:jmespath-java:1.11.792 (*)
|    |    |    +--- com.amazonaws:aws-java-sdk-cloudformation:1.11.792
|    |    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
|    |    |    |    \--- com.amazonaws:jmespath-java:1.11.792 (*)
|    |    |    \--- org.slf4j:slf4j-api:1.7.30
|    |    +--- org.springframework:spring-context:5.2.8.RELEASE -> 5.2.12.RELEASE (*)
|    |    \--- org.slf4j:slf4j-api:1.7.30
|    +--- org.springframework.cloud:spring-cloud-aws-autoconfigure:2.2.5.RELEASE
|    |    +--- org.springframework.cloud:spring-cloud-aws-context:2.2.5.RELEASE (*)
|    |    +--- org.springframework.boot:spring-boot-autoconfigure:2.3.2.RELEASE -> 2.3.7.RELEASE (*)
|    |    \--- org.slf4j:slf4j-api:1.7.30
|    \--- org.slf4j:slf4j-api:1.7.30
\--- org.springframework.cloud:spring-cloud-starter-aws-messaging -> 2.2.5.RELEASE
     +--- org.springframework.cloud:spring-cloud-starter-aws:2.2.5.RELEASE (*)
     +--- org.springframework.cloud:spring-cloud-aws-messaging:2.2.5.RELEASE
     |    +--- org.springframework.cloud:spring-cloud-aws-context:2.2.5.RELEASE (*)
     |    +--- com.amazonaws:aws-java-sdk-sns:1.11.792
     |    |    +--- com.amazonaws:aws-java-sdk-sqs:1.11.792
     |    |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
     |    |    |    \--- com.amazonaws:jmespath-java:1.11.792 (*)
     |    |    +--- com.amazonaws:aws-java-sdk-core:1.11.792 (*)
     |    |    \--- com.amazonaws:jmespath-java:1.11.792 (*)
     |    +--- com.amazonaws:aws-java-sdk-sqs:1.11.792 (*)
     |    +--- org.springframework:spring-messaging:5.2.8.RELEASE -> 5.2.12.RELEASE
     |    |    +--- org.springframework:spring-beans:5.2.12.RELEASE (*)
     |    |    \--- org.springframework:spring-core:5.2.12.RELEASE (*)
     |    \--- org.slf4j:slf4j-api:1.7.30
     \--- org.slf4j:slf4j-api:1.7.30

application.propertiesの定義

AWSにアクセスするのではなく、開発端末でLocalStackを使って疑似サーバーを立ててテストするための設定になっている。

cloud.aws.stack.auto=false
cloud.aws.region.auto=false
cloud.aws.region.static=ap-northeast-1
cloud.aws.credentials.access-key=dummy
cloud.aws.credentials.secret-key=dummy

logging.level.com.amazonaws.util.EC2MetadataUtils=error

aws.endpoint=http://localhost:4566

LocalStackについて

localstack/localstack: 💻 A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline!

  • AWSだと課金が怖いので、まずは開発環境で色々試すためのツール。
  • Dockerで動かす。
  • 今回はWindows 10 Pro の端末上にDockerをインストールして、そのうえで動かした。

docker-compose.yml の内容

初期値のままでも大丈夫だったかもしれないけど、とりあえず動いたときのものを貼り付けておく。

version: '2.1'

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack
    network_mode: bridge
    ports:
      - "4566:4566"
      - "4571:4571"
      - "18080:18080"
    environment:
      - SERVICES=${SERVICES- }
      - DEBUG=${DEBUG- }
      - DATA_DIR=${DATA_DIR- }
      - PORT_WEB_UI=${PORT_WEB_UI- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
      - DOCKER_HOST=unix:///var/run/docker.sock
      - HOST_TMP_FOLDER=${TMPDIR}
      - LAMBDA_DOCKER_NETWORK=host
      - AWS_CBOR_DISABLE=true
      - USE_SSL=false
      - AWS_ACCESS_KEY_ID=dummy
      - AWS_SECRET_ACCESS_KEY=dummy
    volumes:
      - "${TMPDIR:-/tmp/localstack}:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

コマンド集

キューを作成

aws --region ap-northeast-1 --endpoint-url http://localhost:4566 sqs create-queue --queue-name 'foo-queue'

メッセージ送信

aws --region ap-northeast-1 --endpoint-url http://localhost:4566 sqs send-message --queue-url 'http://localhost:4566/000000000000/foo-queue' --message-body 'hogehoge'

動くようになるまでに悩まされたものその1

アプリ起動時にcom.amazonaws.SdkClientException: Failed to connect to service endpoint:エラーが出る

2020-12-15 15:08:00.739  WARN 18360 --- [           main] i.InstanceMetadataServiceResourceFetcher : Fail to retrieve token 

com.amazonaws.SdkClientException: Failed to connect to service endpoint: 
    at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:100) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.getToken(InstanceMetadataServiceResourceFetcher.java:91) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:69) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.internal.EC2ResourceFetcher.readResource(EC2ResourceFetcher.java:66) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.util.EC2MetadataUtils.getItems(EC2MetadataUtils.java:402) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.util.EC2MetadataUtils.getData(EC2MetadataUtils.java:371) ~[aws-java-sdk-core-1.11.792.jar:na]
    at org.springframework.cloud.aws.context.support.env.AwsCloudEnvironmentCheckUtils.isRunningOnCloudEnvironment(AwsCloudEnvironmentCheckUtils.java:38) ~[spring-cloud-aws-context-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.context.annotation.OnAwsCloudEnvironmentCondition.matches(OnAwsCloudEnvironmentCondition.java:38) ~[spring-cloud-aws-context-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:477) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:131) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at com.example.demo.AaaaApplication.main(AaaaApplication.java:21) ~[main/:na]
Caused by: java.net.SocketException: Network is unreachable: connect
    at java.base/java.net.PlainSocketImpl.waitForConnect(Native Method) ~[na:na]
    at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:107) ~[na:na]
    at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) ~[na:na]
    at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242) ~[na:na]
    at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224) ~[na:na]
    at java.base/java.net.Socket.connect(Socket.java:609) ~[na:na]
    at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:177) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:341) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:362) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1253) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1232) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1015) ~[na:na]
    at com.amazonaws.internal.ConnectionUtils.connectToEndpoint(ConnectionUtils.java:52) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:80) ~[aws-java-sdk-core-1.11.792.jar:na]
    ... 25 common frames omitted

検索しまくったところ、EC2 metadata resolution related exception thrown when running application locally · Issue #556 · spring-cloud/spring-cloud-aws を見つけた。

EC2 metadata resolution related exception thrown when running application locally · Issue #556 · spring-cloud/spring-cloud-aws によると、AWS SDK v1 (checked with 1.11.791)からこのエラーが出るようになったらしい。

application.propertiosに以下の記述を追加して回避する。

logging.level.com.amazonaws.util.EC2MetadataUtils=error

動くようになるまでに悩まされたものその2

トークンの認証なんたらとエラーが出る。

2020-12-15 15:23:48.243 ERROR 11644 --- [           main] o.s.boot.SpringApplication               : Application run failed

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: 806c2625-65f0-56f0-95a0-7e773d023d56; Proxy: null)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.7.RELEASE.jar:2.3.7.RELEASE]
    at com.example.demo.AaaaApplication.main(AaaaApplication.java:21) ~[main/:na]
Caused by: 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: 806c2625-65f0-56f0-95a0-7e773d023d56; Proxy: null)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1811) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1395) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1371) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1145) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530) ~[aws-java-sdk-core-1.11.792.jar:na]
    at com.amazonaws.services.sqs.AmazonSQSClient.doInvoke(AmazonSQSClient.java:2207) ~[aws-java-sdk-sqs-1.11.792.jar:na]
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2174) ~[aws-java-sdk-sqs-1.11.792.jar:na]
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2163) ~[aws-java-sdk-sqs-1.11.792.jar:na]
    at com.amazonaws.services.sqs.AmazonSQSClient.executeGetQueueUrl(AmazonSQSClient.java:1201) ~[aws-java-sdk-sqs-1.11.792.jar:na]
    at com.amazonaws.services.sqs.AmazonSQSClient.getQueueUrl(AmazonSQSClient.java:1173) ~[aws-java-sdk-sqs-1.11.792.jar:na]
    at org.springframework.cloud.aws.messaging.support.destination.DynamicQueueUrlDestinationResolver.resolveDestination(DynamicQueueUrlDestinationResolver.java:94) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.support.destination.DynamicQueueUrlDestinationResolver.resolveDestination(DynamicQueueUrlDestinationResolver.java:38) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.messaging.core.CachingDestinationResolverProxy.resolveDestination(CachingDestinationResolverProxy.java:92) ~[spring-messaging-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.queueAttributes(AbstractMessageListenerContainer.java:321) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.initialize(AbstractMessageListenerContainer.java:293) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.initialize(SimpleMessageListenerContainer.java:112) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.afterPropertiesSet(AbstractMessageListenerContainer.java:268) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.afterPropertiesSet(SimpleMessageListenerContainer.java:46) ~[spring-cloud-aws-messaging-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    ... 17 common frames omitted

このエラーが出たときのコードは以下の通り。

package com.example.demo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder;

@Configuration
public class AwsSQSConfig {

    Logger logger = LoggerFactory.getLogger(AwsSQSConfig.class);

    @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;

    @Value("${aws.endpoint}")
    private String endPoint;

    @Bean
    public QueueMessagingTemplate queueMessagingTemplate() {
        return new QueueMessagingTemplate(amazonSQSAsync());
    }

    @Primary
    @Bean
    public AmazonSQSAsync amazonSQSAsync() {

        logger.info("region:{}, awsAccessKey:{}, awsSecretKey:{}", region, awsAccessKey, awsSecretKey);

        AmazonSQSAsync async = AmazonSQSAsyncClientBuilder.standard()
                .withRegion(Regions.AP_NORTHEAST_1)
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
                //.withEndpointConfiguration(new EndpointConfiguration(endPoint, region))
                .build();
        
        return async;
    }

}

デバッグで追いかけたところ、エンドポイントのURLがlocalhostになっていなかった。(指定していないから当たり前) 以下のように修正してみる。

   @Primary
    @Bean
    public AmazonSQSAsync amazonSQSAsync() {

        logger.info("region:{}, awsAccessKey:{}, awsSecretKey:{}", region, awsAccessKey, awsSecretKey);

        AmazonSQSAsync async = AmazonSQSAsyncClientBuilder.standard()
                .withRegion(Regions.AP_NORTHEAST_1)
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
                .withEndpointConfiguration(new EndpointConfiguration(endPoint, region))
                .build();
        
        return async;
    }

今度は以下のエラーが出る。

Caused by: java.lang.IllegalStateException: Only one of Region or EndpointConfiguration may be set.
    at com.amazonaws.client.builder.AwsClientBuilder.setRegion(AwsClientBuilder.java:450) ~[aws-java-sdk-core-1.11.792.jar:na]

リージョンは複数セットできないよ、ということらしい。(それはそう)

‘withRegion()`の部分を削除することで正常に立ち上がった。

   @Primary
    @Bean
    public AmazonSQSAsync amazonSQSAsync() {

        logger.info("region:{}, awsAccessKey:{}, awsSecretKey:{}", region, awsAccessKey, awsSecretKey);

        AmazonSQSAsync async = AmazonSQSAsyncClientBuilder.standard()
                //.withRegion(Regions.AP_NORTHEAST_1)
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
                .withEndpointConfiguration(new EndpointConfiguration(endPoint, region))
                .build();
        
        return async;
    }

SQSにプットされたら自動で受信処理が動くようにする

org.springframework.cloud.aws.messaging.listener.annotation.SqsListener を使う。

package com.example.demo.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
import org.springframework.stereotype.Component;

@Component
public class AwsSQSListener {

    Logger logger= LoggerFactory.getLogger(AwsSQSListener.class);

    @SqsListener("foo-queue")
    public void loadMessageFromSQS(String message)  {
        logger.info("message from SQS Queue {}",message);
    }
}

aws lambdaを使うより、常駐のSpringアプリケーションを一つ用意して、このアプリ内でリスナーを立ち上げたほうが色々やりやすそうな感じを受けた。