== 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 https://aws.amazon.com/elasticache/[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
https://projects.spring.io/spring-data-redis/[Spring Data Redis] for Redis caches.

=== 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

[source,xml,indent=0]
----
<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.

=== 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.

[source,xml,indent=0]
----
<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
	   	https://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
https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/ManagingCacheClusters.html[ElasticCache cluster].

==== 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.

[source,xml,indent=0]
----
<beans ...>
	<aws-cache:cache-manager id="cacheManager">
		<aws-cache:cache-ref ref="memcached" />
		<aws-cache:cache-cluster name="SimpleCache"/>
	</aws-cache:cache-manager>
</beans>
----

==== 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.

[source,xml,indent=0]
----
<beans>
	<aws-cache:cache-manager>
		<aws-cache:cache-cluster expiration="10000" name="CacheCluster" />
	</aws-cache:cache-manager>
</beans>
----

=== 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 `io.awspring.cloud.cache.config.annotation.EnableElastiCache`
annotation provided by Spring Cloud AWS. The next example shows a configuration of two cache clusters.

CAUTION: Since 2.3.0 `@EnableElastiCache` annotation has been deprecated. We suggest using Spring Boot auto-configuration instead.

[source,java,indent=0]
----

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

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

==== 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.

[source,java,indent=0]
----

@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).

[source,java,indent=0]
----

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


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

=== 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

[source,java,indent=0]
----
@Service
public class ExpensiveService {

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

=== Memcached client implementation
There are different memcached client implementations available for Java, the most prominent ones are
https://github.com/couchbase/spymemcached[Spymemcached] and https://github.com/killme2008/xmemcached[XMemcached].
Amazon AWS supports a dynamic configuration and delivers an enhanced memcached client based on Spymemcached to support the
https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html[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.

=== 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.

[source,json,indent=0]
----
"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:

[source,xml,indent=0]
----
<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.

=== IAM Permissions
Following IAM permissions are required by Spring Cloud AWS:

[cols="2"]
|===
| To configure to ElastiCache you will need:
| `elasticache:DescribeCacheClusters`



|===

Sample IAM policy granting access to ElastiCache:

[source,json,indent=0]
----
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "elasticache:DescribeCacheClusters",
            "Resource": "yourArn"
        }
    ]
}
----
