6. Caching

Caching in a cloud environment is useful for applications to reduce the latency and to save database round trips. Reducing database round trips can significantly reduce the requirements for the database instance. The Spring Framework provides, since version 3.1, a unified Cache abstraction to allow declarative caching in applications analogous to the declarative transactions.

Spring Cloud AWS integrates the Amazon ElastiCache service into the Spring unified caching abstraction providing a cache manager based on the memcached and Redis protocols. The caching support for Spring Cloud AWS provides its own memcached implementation for ElastiCache and uses Spring Data Redis for Redis caches.

6.1 Configuring dependencies for Redis caches

Spring Cloud AWS delivers its own implementation of a memcached cache, therefore no other dependencies are needed. For Redis Spring Cloud AWS relies on Spring Data Redis to support caching and also to allow multiple Redis drivers to be used. Spring Cloud AWS supports all Redis drivers that Spring Data Redis supports (currently Jedis, JRedis, SRP and Lettuce) with Jedis being used internally for testing against ElastiCache. A dependency definition for Redis with Jedis is shown in the example

<dependencies>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>${spring-data-redis.version}</version>
    </dependency>
    <dependency>
    	<groupId>redis.clients</groupId>
    	<artifactId>jedis</artifactId>
    	<version>2.6.1</version>
    </dependency>
</dependencies>

Spring Cloud AWS will automatically detect the Redis driver and will use one of them automatically.

6.2 Configuring caching with XML

The cache support for Spring Cloud AWS resides in the context module and can therefore be used if the context module is already imported in the project. The cache integration provides its own namespace to configure cache clusters that are hosted in the Amazon ElastiCache service. The next example contains a configuration for the cache cluster and the Spring configuration to enable declarative, annotation-based caching.

<beans xmlns:aws-cache="http://www.springframework.org/schema/cloud/aws/cache"
	   xmlns:cache="http://www.springframework.org/schema/cache"
	   xmlns="http://www.springframework.org/schema/beans"
	   xsi:schemaLocation="http://www.springframework.org/schema/cloud/aws/cache
	   	http://www.springframework.org/schema/cloud/aws/cache/spring-cloud-aws-cache.xsd
	   	http://www.springframework.org/schema/cache
	   	http://www.springframework.org/schema/cache/spring-cache.xsd">

	<aws-context:context-credentials>
		...
        </aws-context:context-credentials>

	<aws-cache:cache-manager>
		<aws-cache:cache-cluster name="CacheCluster" />
	</aws-cache:cache-manager>

	<cache:annotation-driven />
</beans>

The configuration above configures a cache-manager with one cache with the name CacheCluster that represents an ElasticCache cluster.

6.2.1 Mixing caches

Applications may have the need for multiple caches that are maintained by one central cache cluster. The Spring Cloud AWS caching support allows to define multiple caches inside one cache manager and also to use externally defined caches inside the cache manager.

The example below demonstrates a configuration example that contains a pre-configured cache with a cache-ref element (which might be a local cache) and a cache-cluster configuration for ElastiCache cache clusters.

<beans ...>
	<aws-cache:cache-manager id="cacheManager">
		<aws-cache:cache-ref ref="memcached" />
		<aws-cache:cache-cluster name="SimpleCache"/>
	</aws-cache:cache-manager>
</beans>

6.2.2 Defining expiration

The Spring cache demarcation does not support expiry time configuration and leaves it up to the cache implementation to support an expiry time. The Spring Cloud AWS cache configuration supports the expiry time setting per cache. The expiry time will be passed to the memcached service.

The cache-cluster element accepts an expiration attribute that defines the expiration time in seconds. No configured values implies that there is an infinite expiration time.

<beans>
	<aws-cache:cache-manager>
		<aws-cache:cache-cluster expiration="10000" name="CacheCluster" />
	</aws-cache:cache-manager>
</beans>

6.3 Configuring caching using Java configuration

Spring Cloud AWS also support the cache configuration with Java configuration classes. On any Configuration class, the caching can be configured using the org.springframework.cloud.aws.cache.config.annotation.EnableElastiCache annotation provided by Spring Cloud AWS. The next example shows a configuration of two cache clusters.

@EnableElastiCache({@CacheClusterConfig(name = "firstCache"), @CacheClusterConfig(name = "secondCache")})
public class ApplicationConfiguration {
}
[Important]Important

If you leave the value attribute empty, then all the caches inside your CloudFormation stack (if available) will be configured automatically.

6.3.1 Configuring expiry time for caches

The Java configuration also allows to configure the expiry time for the caches. This can be done for all caches using the defaultExpiration attribute as shown in the example below.

@EnableElastiCache(defaultExpiration = 23)
public class ApplicationConfiguration {
}

The expiration can be defined on a cache level using the @CacheClusterConfig annotations expiration attribute as shown below (using seconds as the value).

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

6.4 Configuring caching in Spring Boot

The caches will automatically be configured in Spring Boot without any explicit configuration property.

6.5 Using caching

Based on the configuration of the cache, developers can annotate their methods to use the caching for method return values. The next example contains a caching declaration for a service for which the return values should be cached

@Service
public class ExpensiveService {

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

6.6 Memcached client implementation

There are different memcached client implementations available for Java, the most prominent ones are Spymemcached and XMemcached. Amazon AWS supports a dynamic configuration and delivers an enhanced memcached client based on Spymemcached to support the auto-discovery of new nodes based on a central configuration endpoint.

Spring Cloud AWS relies on the Amazon ElastiCache Client implementation and therefore has a dependency on that.

6.7 Using CloudFormation

Amazon ElastiCache clusters can also be configured within a stack and then be used by applications. Spring Cloud AWS also supports the lookup of stack-configured cache clusters by their logical name with the resolution to the physical name. The example below shows a cache cluster configuration inside a CloudFormation template.

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

The cache cluster can then be used with the name CacheCluster inside the application configuration as shown below:

<beans...>
    <aws-cache:cache-manager>
    	<aws-cache:cache-cluster name="CacheCluster" expiration="15"/>
    </aws-cache:cache-manager>
<beans>

With the configuration above the application can be deployed with multiple stacks on different environments without any configuration change inside the application.