Integrate your Spring Boot application with AWS

AWS Cloud spring-boot

So you’ve heard to cloud is hot and your team has decided your Spring Boot application must integrate with it. But what does integration with the cloud exactly mean? In this blogpost I’ll walk you through ways to integrate your Spring Boot application with AWS. Spring Cloud makes interacting with AWS services super easy and you can stay safely in you Spring Boot annotation comfort zone. This post will cover four subjects; managing configuration, messaging, caching and infrastructure as a code.

Preparation: defining SDK credentials

To be able to interact with AWS services, SDK credentials need to be configured. These credentials can be created in the IAM service of AWS. There are multiple options for setting the configuration in your application but the most easy and flexible way is to use Spring properties to define credentials. (cloud.aws.credentials.accessKey and cloud.aws.credentials.secretKey). To make this work the spring-cloud-aws-autoconfigure module needs to be added to your maven/gradle project.

Managing configuration

Keeping track and managing of all your environment and application specific properties can be a nightmare. Luckily Spring Cloud integrates with the AWS Systems Manager Parameter Store. The parameter store provides a secure and centralised solution for managing configuration. The parameter store can be found below the AWS Systems Manager service.

When the spring-cloud-starter-aws-parameter-store-config module is added to your project, the service will automatically use properties from the parameter store. The convention for properties of the application with name ‘demo-app’ is as follows:

Spring property: spring.datasource.url
Parameter store: /config/demo-app/spring/datasource/url

When a Spring profile is activated, it will search for parameters specific to this profile. Below an example where the ‘production’ profile is activated.

Spring property: spring.datasource.url
Parameter store: /config/demo-app_production/spring/datasource/url

Messaging

The main AWS messaging services are SNS and SQS. The spring-cloud-aws-messaging module makes interacting – sending and receiving messages / notification – super easy. For sending messages the QueueMessagingTemplate can be used:

java
import com.amazonaws.services.sqs.AmazonSQS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.messaging.support.MessageBuilder;

public class SqsQueueSender {

    private final QueueMessagingTemplate queueMessagingTemplate;

    @Autowired
    public SqsQueueSender(AmazonSQS amazonSqs) {
        this.queueMessagingTemplate = new QueueMessagingTemplate(amazonSqs);
    }

    public void send(String message) {
        this.queueMessagingTemplate.send("physicalQueueName", MessageBuilder.withPayload(message).build());
    }
}

Receiving message is as easy as adding an annotation to a method with a specific queue name

java
@SqsListener("queueName")
public void queueListener(Person person) {
    // ...
}

Caching

Since Spring v3.1 a unified cache abstraction is added to the framework. This abstraction is based on caching on method level, each time a targeted method is invoked, the abstraction will apply a caching behavior checking whether the method has been already executed for the given arguments. If it has, then the cached result is returned without having to execute the actual method.  Spring Cloud AWS now integrates the AWS ElastiCache into this unified cache abstraction. ElastiCache is a Fully managed in-memory data store, compatible with Redis or Memcached. In Both Memcached and Redis is integrated in Spring cloud AWS, for Memcached an custom implementation is created and for Redis the existing Spring data redis module is used.

Configuring the caching can be done using an annotation on any class with the @Configuration annotation. The expiration can be specified for a specific cluster and is a value in seconds. Setting caches can be done using the @Cacheable annotation with the cache cluster as value.

java
@EnableElastiCache({@CacheClusterConfig(name = "firstCache", expiration = 23), @CacheClusterConfig(name = "secondCache")})
@Configuration
public class ApplicationConfiguration {
}

@Service
public class ExpensiveService {

    @Cacheable("CacheCluster")
    public String calculateExpensiveValue(String key) {
        ...
    }
}

Cloudformation

Cloud environments like AWS can become very complex pretty easily. Setting up an environment requires much more than just deploying an application, you have to think about things like VPC’s, Gateways, Databases and Queue’s. Also, for all the different components you need to specify what type of instance (micro, medium, large, etc.) you want to spin up. AWS has build CloudFormation for this particular use case and – not surprisingly – Spring Cloud supports this! CloudFormation is – what they call – infrastructure as Code and uses a JSON file that specifies what components you want to spin up. Below an example on how the integration works between Spring Cloud and CloudFormation:

Below an fragment from a cloudformation file where cache is being specified, please note that the logic name (MyAppCacheCluster) can be specified by the developer.

json
"MyAppCacheCluster": {
    "Type": "AWS::ElastiCache::CacheCluster",
    "Properties": {
        "AutoMinorVersionUpgrade": "true",
        "Engine": "memcached",
        "CacheNodeType": "cache.t2.micro",
        "CacheSubnetGroupName" : "sample",
        "NumCacheNodes": "1",
        "VpcSecurityGroupIds": ["sample1"]
    }
}

If you want to use the created "MyAppCacheCluster" in your app, you can just specify this name as your cluster name in your cache configuration. The only requirement is that, within the CloudFormation file, you also specify to deploy your application using this cache.

java
@EnableElastiCache({@CacheClusterConfig(name = "MyAppCacheCluster", expiration = 23)})
@Configuration
public class ApplicationConfiguration {
}

AWS Cloud spring-boot