diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java index 6a37d350e..ac2985358 100644 --- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java +++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java @@ -36,10 +36,14 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; import software.amazon.awssdk.regions.providers.AwsRegionProvider; +import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; +import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClientBuilder; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder; +import software.amazon.dax.ClusterDaxAsyncClient; import software.amazon.dax.ClusterDaxClient; /** @@ -51,7 +55,7 @@ */ @AutoConfiguration @EnableConfigurationProperties(DynamoDbProperties.class) -@ConditionalOnClass({ DynamoDbClient.class, DynamoDbEnhancedClient.class, DynamoDbTemplate.class }) +@ConditionalOnClass({ DynamoDbClient.class, DynamoDbAsyncClient.class}) @AutoConfigureAfter({ CredentialsProviderAutoConfiguration.class, RegionProviderAutoConfiguration.class }) @ConditionalOnProperty(name = "spring.cloud.aws.dynamodb.enabled", havingValue = "true", matchIfMissing = true) public class DynamoDbAutoConfiguration { @@ -93,6 +97,39 @@ public DynamoDbClient dynamoDbClient(DynamoDbProperties properties, AwsCredentia return ClusterDaxClient.builder().overrideConfiguration(configuration.build()).build(); } + @ConditionalOnMissingBean + @Bean + public DynamoDbAsyncClient dynamoDbAsyncClient(DynamoDbProperties properties, + AwsCredentialsProvider credentialsProvider, + AwsRegionProvider regionProvider) throws IOException { + DaxProperties daxProperties = properties.getDax(); + + PropertyMapper propertyMapper = PropertyMapper.get(); + software.amazon.dax.Configuration.Builder configuration = software.amazon.dax.Configuration.builder(); + propertyMapper.from(daxProperties.getIdleTimeoutMillis()).whenNonNull() + .to(configuration::idleTimeoutMillis); + propertyMapper.from(daxProperties.getConnectionTtlMillis()).whenNonNull() + .to(configuration::connectionTtlMillis); + propertyMapper.from(daxProperties.getConnectTimeoutMillis()).whenNonNull() + .to(configuration::connectTimeoutMillis); + propertyMapper.from(daxProperties.getRequestTimeoutMillis()).whenNonNull() + .to(configuration::requestTimeoutMillis); + propertyMapper.from(daxProperties.getWriteRetries()).whenNonNull().to(configuration::writeRetries); + propertyMapper.from(daxProperties.getReadRetries()).whenNonNull().to(configuration::readRetries); + propertyMapper.from(daxProperties.getClusterUpdateIntervalMillis()).whenNonNull() + .to(configuration::clusterUpdateIntervalMillis); + propertyMapper.from(daxProperties.getEndpointRefreshTimeoutMillis()).whenNonNull() + .to(configuration::endpointRefreshTimeoutMillis); + propertyMapper.from(daxProperties.getMaxConcurrency()).whenNonNull().to(configuration::maxConcurrency); + propertyMapper.from(daxProperties.getMaxPendingConnectionAcquires()).whenNonNull() + .to(configuration::maxPendingConnectionAcquires); + propertyMapper.from(daxProperties.getSkipHostNameVerification()).whenNonNull() + .to(configuration::skipHostNameVerification); + + configuration.region(AwsClientBuilderConfigurer.resolveRegion(properties, regionProvider)) + .credentialsProvider(credentialsProvider).url(properties.getDax().getUrl()); + return ClusterDaxAsyncClient.builder().overrideConfiguration(configuration.build()).build(); + } } @Conditional(MissingDaxUrlCondition.class) @@ -109,12 +146,37 @@ public DynamoDbClient dynamoDbClient(AwsClientBuilderConfigurer awsClientBuilder } + @Conditional(MissingDaxUrlCondition.class) + @Configuration(proxyBeanMethods = false) + static class StandardDynamoDbAsyncClient { + + @ConditionalOnMissingBean + @Bean + public DynamoDbAsyncClient dynamoDbAsyncClient( + AwsClientBuilderConfigurer awsClientBuilderConfigurer, + ObjectProvider> configurer, + DynamoDbProperties properties) { + return awsClientBuilderConfigurer + .configure(DynamoDbAsyncClient.builder(), properties, configurer.getIfAvailable()).build(); + } + + } + @ConditionalOnMissingBean + @ConditionalOnClass(DynamoDbEnhancedClient.class) @Bean public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) { return DynamoDbEnhancedClient.builder().dynamoDbClient(dynamoDbClient).build(); } + @ConditionalOnMissingBean + @ConditionalOnClass(DynamoDbEnhancedAsyncClient.class) + @Bean + public DynamoDbEnhancedAsyncClient dynamoDbEnhancedClient(DynamoDbAsyncClient dynamoDbClient) { + return DynamoDbEnhancedAsyncClient.builder().dynamoDbClient(dynamoDbClient).build(); + } + + @ConditionalOnClass(DynamoDbTemplate.class) @ConditionalOnMissingBean(DynamoDbOperations.class) @Bean public DynamoDbTemplate dynamoDBTemplate(DynamoDbProperties properties, diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java index 178327a74..4f6df76e9 100644 --- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java +++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java @@ -40,8 +40,10 @@ import software.amazon.awssdk.enhanced.dynamodb.TableSchema; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.apache.ApacheHttpClient; +import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder; +import software.amazon.dax.ClusterDaxAsyncClient; import software.amazon.dax.ClusterDaxClient; /** @@ -96,6 +98,7 @@ void withDynamoDbClientCustomEndpoint() { contextRunner.withPropertyValues("spring.cloud.aws.dynamodb.endpoint:http://localhost:8090") .run(context -> { assertThat(context).hasSingleBean(DynamoDbClient.class); + assertThat(context).hasSingleBean(DynamoDbAsyncClient.class); assertThat(context).hasSingleBean(DynamoDbTemplate.class); assertThat(context).hasSingleBean(DynamoDbEnhancedClient.class); @@ -109,6 +112,7 @@ void withDynamoDbClientCustomEndpoint() { void dynamoDbClientConfiguredSinceNoUrl() { contextRunner.run(context -> { assertThat(context).hasSingleBean(DynamoDbClient.class); + assertThat(context).hasSingleBean(DynamoDbAsyncClient.class); assertThat(context).hasSingleBean(DynamoDbTemplate.class); assertThat(context).hasSingleBean(DynamoDbEnhancedClient.class); assertThat(context).doesNotHaveBean(ClusterDaxClient.class); @@ -170,6 +174,7 @@ void defaultsAreUsedWhenPropertiesAreNotSet() { .run(context -> { ConfiguredDaxClient daxClient = new ConfiguredDaxClient( context.getBean(ClusterDaxClient.class)); + assertThat(context).hasSingleBean(ClusterDaxAsyncClient.class); assertThat(daxClient.getUrl()) .isEqualTo("dax://something.dax-clusters.us-east-1.amazonaws.com"); assertThat(daxClient.getWriteRetries()).isEqualTo(2); @@ -211,6 +216,7 @@ void clusterDaxClient_CustomUrl_DefaultValues() { .run(context -> { ConfiguredDaxClient daxClient = new ConfiguredDaxClient( context.getBean(ClusterDaxClient.class)); + assertThat(context).hasSingleBean(ClusterDaxAsyncClient.class); assertThat(daxClient.getUrl()) .isEqualTo("dax://something.dax-clusters.us-east-1.amazonaws.com"); assertThat(daxClient.getWriteRetries()).isEqualTo(2); @@ -237,6 +243,7 @@ void customTableResolverResolverCanBeConfigured() { assertThat(dynamoDBDynamoDbTableNameResolver) .isInstanceOf(CustomDynamoDBDynamoDbTableNameResolver.class); + assertThat(context).hasSingleBean(ClusterDaxAsyncClient.class); }); }