Spring Cloud AWS
repository·main·Indexed 22 days ago
https://github.com/awspring/spring-cloud-awsA set of libraries that simplify the integration of AWS managed services into Spring and Spring Boot applications. It provides idiomatic abstractions for services including S3, SQS, SNS, SES, Parameter Store, Secrets Manager, CloudWatch, AppConfig, and DynamoDB. The project supports different versions of Spring Boot and the AWS Java SDK, offering features such as annotation-driven SQS message processing with @SqsListener and external configuration loading via spring.config.import.
What's inside Spring Cloud AWS
- Spring Cloud AWS is a framework designed to simplify the integration of AWS managed services into Spring and Spring Boot applications. It provides a way to interact with AWS services using standard Spring idioms and APIs, making AWS integration feel native to the Spring ecosystem.
Handle FIFO SQS queues
mainSpring Cloud AWS provides full support for FIFO SQS queues (queues ending in
.fifo).Key FIFO Behaviors
- Ordering: Messages are polled with a
receiveRequestAttemptId. The batch is split byMessageGroupId. Messages within a group are processed in order, while different groups are processed in parallel. - Batching Strategy: To receive messages from multiple groups in a single batch, set
fifoBatchGroupingStrategytoPROCESS_MULTIPLE_GROUPS_IN_SAME_BATCHinSqsContainerOptions. - Failure Handling: If processing fails for a message, subsequent messages in the same group are discarded and will be served again after the
message visibilityexpires. - Visibility: If visibility is set via
@SqsListenerorSqsContainerOptions, it is extended for all messages in the message group before processing starts.
Important: A
MessageListenerContainercan support either Standard queues or FIFO queues, but not both simultaneously.- Ordering: Messages are polled with a
Spring Integration support for DynamoDB
mainSpring Cloud AWS provides components for Spring Integration to use DynamoDB as a backend:
DynamoDbMetadataStore: An implementation ofConcurrentMetadataStorefor storing key-value entries. It requires aDynamoDbAsyncClientand uses the default table nameSpringIntegrationMetadataStore. It automatically creates the table if it doesn't exist.DynamoDbLockRegistry: An implementation ofExpirableLockRegistryandRenewableLockRegistryfor distributed locking. It requires aDynamoDbAsyncClientand uses the default table nameSpringIntegrationLockRegistry.
How automatic payload type inference works
mainSince version 4.0.0, the framework automatically infers the payload type from the
@SqsListenermethod signature at theMessageSourcelevel. This allows payloads to be deserialized early in the flow, enabling access to deserialized payloads inMessageInterceptor,ErrorHandler, andAcknowledgementResultCallbackwithout requiring type information in message headers.Supported types include:
- Simple types
- Generic types (e.g.,
List<MyEvent>) Message<MyEvent>List<Message<MyEvent>>
Parameters annotated with
@Payloadare explicitly recognized. For polymorphic types (interfaces orObject), a custompayloadTypeMapperis required.How Kinesis consumer groups work
mainAWS Kinesis does not support consumer groups natively. The Kinesis Binder implements this using a
MetadataStore(for shard checkpoints) and aLockRegistry(to ensure exclusive shard access).To achieve a highly available (HA) consumer group:
- Ensure all instances use a shared
DynamoDbMetadataStoreandDynamoDbLockRegistry. - Use the same group name for the channel across all instances via
spring.cloud.stream.bindings.<bindingTarget>.group.
Note on Distribution: Even distribution across instances is not guaranteed. A single instance might pick up all shards. To improve throughput, configure consumer concurrency using
spring.cloud.stream.bindings.<bindingTarget>.consumer.concurrency.For static shard distribution, you can manually balance shards by setting:
spring.cloud.stream.instanceCountto the total number of instances.spring.cloud.stream.instanceIndexto the current instance's index.
- Ensure all instances use a shared
Access S3 objects as Spring Resources
mainSpring Cloud AWS provides
S3Resourceobjects, allowing you to treat S3 objects as standard SpringResourceabstractions using thes3://protocol. You can access them via@Valueor theApplicationContext.Key behaviors:
- URL Format:
s3://[S3_BUCKET_NAME]/[FILE_NAME] - Trailing Slashes: As of version
4.1.0, trailing slashes are preserved.s3://my-bucket/path/resolves to the prefixpath/. This allows using S3 prefixes as Spring static resource locations. - Writing: To write to a resource, it must be cast to
WritableResourceorS3Resource(to set metadata).
// Using @Value @Value("s3://my-bucket/file.txt") private Resource s3Resource; // Using ApplicationContext Resource res = SpringApplication.run(...).getResource("s3://my-bucket/file.txt"); // Writing with metadata ObjectMetadata metadata = ObjectMetadata.builder() .contentType("application/json") .serverSideEncryption(ServerSideEncryption.AES256) .build(); ((S3Resource) s3Resource).setObjectMetadata(metadata); try (OutputStream os = s3Resource.getOutputStream()) { os.write("content".getBytes()); }- URL Format:
Configure AWS Credentials
mainSpring Cloud AWS uses
software.amazon.awssdk.auth.credentials.AwsCredentialsProviderto authenticate calls to AWS. You can configure credentials in three ways:DefaultCredentialsProvider: The starter auto-configures this, which searches in the following order:
- Java system properties (
aws.accessKeyId,aws.secretAccessKey) - Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) - Web identity token credentials
- Credential profiles file (
~/.aws/credentials) - Amazon EC2 container credentials (
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) - EC2 instance profile credentials
- Java system properties (
StsWebIdentityTokenFileCredentialsProvider: Recommended for EKS/Kubernetes environments to assume IAM roles via web identity tokens. Requires the
software.amazon.awssdk:stsdependency.Custom AwsCredentialsProvider: Define your own bean to override auto-configuration.
@Configuration class CustomCredentialsProviderConfiguration { @Bean public AwsCredentialsProvider customAwsCredentialsProvider() { return new CustomAWSCredentialsProvider(); } }Understand the SQS runtime processing pipeline
mainThe runtime execution of an SQS listener follows a composable four-stage pipeline. Each stage can be extended or swapped by implementing specific interfaces:
- Ingress (MessageSource): Polls SQS for messages and converts them into Spring
Messageobjects. It uses aBackPressureHandlerto manage in-flight capacity. - Dispatch (MessageSink): Routes messages to the processing pipeline. Common implementations include:
FanOutMessageSink: For single-message dispatch.BatchMessageSink: For batch processing.OrderedMessageSink: For maintaining order.MessageGroupingSinkAdapter: For FIFO queue grouping.
- Processing (MessageProcessingPipeline): The core logic chain consisting of:
MessageInterceptor: Hooks for logic before or after processing.MessageListener: The component that actually invokes your@SqsListenermethod.ErrorHandler: Manages failures during processing.AcknowledgementHandler: Triggers the deletion of the message from SQS.
- Acknowledgement (AcknowledgementProcessor): Performs the actual deletion of processed messages from SQS and notifies an
AcknowledgementResultCallbackupon success or failure.
- Ingress (MessageSource): Polls SQS for messages and converts them into Spring
Configure SQS Message Acknowledgement Strategies
mainIn SQS, acknowledging a message is equivalent to deleting it. You can configure acknowledgement behavior via
SqsContainerOptionsor the@SqsListenerannotation usingAcknowledgementMode:ON_SUCCESS: Acknowledges after successful processing.ALWAYS: Acknowledges after processing returns success or error.MANUAL: Framework does not acknowledge automatically; you must useAcknowledgementorBatchAcknowledgementobjects in your listener.
Batching Options: Use
acknowledgementIntervalandacknowledgementThresholdto batch acknowledgements.Immediate Acknowledging: Set both toDuration.ZEROand0respectively. Messages are acknowledged sequentially after processing.
Ordering Options:
PARALLEL: Many calls can be made in parallel.ORDERED: One batch is executed after the previous one completes (ensures FIFO for batching).ORDERED_BY_GROUP: Ensures FIFO ordering per message group (only for FIFO queues).
@Bean SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory(SqsAsyncClient sqsAsyncClient) { return SqsMessageListenerContainerFactory .builder() .configure(options -> options .acknowledgementMode(AcknowledgementMode.ALWAYS) .acknowledgementInterval(Duration.ofSeconds(3)) .acknowledgementThreshold(5) .acknowledgementOrdering(AcknowledgementOrdering.ORDERED) ) .sqsAsyncClient(sqsAsyncClient) .build(); }How Spring Cloud AWS SQS works: The Two-Phase Architecture
mainThe SQS integration operates using a two-phase architecture that separates startup configuration from message processing:
Assembly Phase (Startup): Spring detects
@SqsListenerannotations, createsEndpointobjects, and uses theSqsMessageListenerContainerFactoryto createMessageListenerContainerinstances. These containers are then managed by theMessageListenerContainerRegistry.Runtime Phase (Execution): Once containers start, they run an asynchronous, non-blocking pipeline. This pipeline uses the AWS SDK v2
SqsAsyncClientto poll SQS, invoke your listener, and acknowledge (delete) messages without tying up threads, making the system highly scalable for I/O-bound operations.
GraalVM Native Image Support
mainSpring Cloud AWS provides experimental support for GraalVM Native Image (since version 3.3.0).
Known limitations/requirements:
- DynamoDB: You must use
StaticTableSchemainstead ofDynamicTableSchema. - S3: If using the CRT client, you must follow the specific AWS CRT GraalVM support guide.
- DynamoDB: You must use
Access JSON and plain text secrets
mainOnce imported, secrets are available in the Spring environment.
JSON Secrets
When a
SecretStringcontains JSON, all top-level keys are added as individual properties. For a secret containing{"username": "saanvi", "password": "EXAMPLE-PASSWORD"}, you can access them via@Valueor@ConfigurationProperties.Plain Text Secrets
For plain text secrets, the value is retrieved by referencing the secret name (or the key assigned to it). For example, if a secret named
/secrets/prod/jdbc-urlcontains a JDBC URL, you can use it in your properties file.Adding a Property Prefix
To prevent collisions, you can add a prefix to all keys within a secret using the
?prefix=syntax in the import string. Note: If you want a dot between the prefix and the key, include a trailing dot in the prefix value.Example:
spring.config.import=aws-secretsmanager:/secrets/database-secrets?prefix=db.will turnusernameintodb.username.// Accessing JSON keys @Value("${username}") private String username; @Value("${password}") private String password;