DynamoDB and Spring Boot
8 Jul 2019
java
spring
aws
dynamodb
At work we were recently looking into setting up somethings in DynamoDB with Spring Boot for the first time as a team. We hit up Google and ended up on this page, https://www.baeldung.com/spring-data-dynamodb. Within a couple of seconds of reading there were a couple issues with this article that made we want to write this post. Now I know there are going to be issues with this post as well but I’m covering the big ones that were in that post.
Issue #1: AWS properties in application.properties
In step 4 of the article it has you set-up the configuration for you application. Inside the application file it has you define amazon.aws.accesskey
and amazon.aws.secretkey
inside the application.properties
. There are many security issues that arise from doing it this way, but my biggest complaint is that it doesn’t use the Amazon specification of DefaultAWSCredentialsProviderChain.
The DefaultAWSCredentialsProviderChain
is the recommended, though not required, way of utilizing the AWS SDK. More documentation can be found here, https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html. This would allow us to move our application from development to production while utilizing local keys in development and EC2 AMI Roles in production.
Issue #2: Not utilizing the SDK builders
Again in step 4 we have the following @Bean
definition
@Bean
public AmazonDynamoDB amazonDynamoDB() {
AmazonDynamoDB amazonDynamoDB
= new AmazonDynamoDBClient(amazonAWSCredentials());
if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
}
return amazonDynamoDB;
}
This creates a com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient
object directly, which is @Deprecated
in favour of the com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder
. The builder gives a cleaner, more concise and non-deprecated version of creating your com.amazonaws.services.dynamodbv2.AmazonDynamoDB
.
Issue #3: Using field-based injection
Sticking with a theme of step 4, the values in the DynamoDBConfig
are configured using field-based injection. I’ve covered why field-based injection should be avoided in a previous post Spring Dependecy Injection. We can quickly fix this by utilizing contructor-based injection.
@Configuration
@EnableDynamoDBRepositories
(basePackages = "com.baeldung.spring.data.dynamodb.repositories")
public class DynamoDBConfig {
private final String amazonDynamoDBEndpoint;
private final String amazonAWSAccessKey;
private final String amazonAWSSecretKey;
public DynamoDBConfig(@Value("${amazon.dynamodb.endpoint}") String amazonDynamoDBEndpoint, @Value("${amazon.aws.accesskey}") String amazonAWSAccessKey, @Value("${amazon.aws.secretkey}") String amazonAWSSecretKey) {
this.amazonDynamoDBEndpoint = amazonDynamoDBEndpoint;
this.amazonAWSAccessKey = amazonAWSAccessKey;
this.amazonAWSSecretKey = amazonAWSSecretKey;
}
@Bean
public AmazonDynamoDB amazonDynamoDB() {
AmazonDynamoDB amazonDynamoDB
= new AmazonDynamoDBClient(amazonAWSCredentials());
if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
}
return amazonDynamoDB;
}
@Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(
amazonAWSAccessKey, amazonAWSSecretKey);
}
}
Those are the issues that I have with the article. I know that no article is perfect and that it’s up to the reader to properly implement the solutions provided because, sadly, we live in world of “this article/post told me to do it this way” so I’m going to take that as gospel.
Conclusion
One thing I would have like to see from the article would be to have it utilize more Springy things to do the configuration. In the article they’re checking for !StringUtils.isEmpty(amazonDynamoDBEndpoint)
to see if the endpoint should be configured. Instead of using the StringUtils
we could use beans to configure the endpoind, if needed.
@Bean
@ConditionalOnProperty("dynamodb.url")
public AwsClientBuilder.EndpointConfiguration endpointConfiguration(@Value("${dynamodb.url}") String dynamodbUrl,
@Value("${dynamodb.region:us-east-1}") String dynamodbRegion) {
return new AwsClientBuilder.EndpointConfiguration(dynamodbUrl, dynamodbRegion);
}
@Bean
public AmazonDynamoDB amazonDynamoDB(@Autowired(required = false) AwsClientBuilder.EndpointConfiguration endpointConfiguration) {
return AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(endpointConfiguration).build();
}
This allows us to use Spring beans to configure the builder without having to do logic checks on where the property exists or not.