[[io.caching]]
= Caching

The Spring Framework provides support for transparently adding caching to an application.
At its core, the abstraction applies caching to methods, thus reducing the number of executions based on the information available in the cache.
The caching logic is applied transparently, without any interference to the invoker.
For more details, check the {url-spring-framework-docs}/integration/cache.html[relevant section] of the Spring Framework reference documentation.

Spring Boot auto-configures the cache infrastructure as long as caching support is enabled by using the javadoc:org.springframework.cache.annotation.EnableCaching[format=annotation] annotation.

TIP: Avoid adding javadoc:org.springframework.cache.annotation.EnableCaching[format=annotation] to the main method's application class.
Doing so makes caching a mandatory feature, including xref:io/caching.adoc#io.caching.testing[when running a test suite].

To add caching to an operation of your service add the relevant annotation to its method, as shown in the following example:

include-code::MyMathService[]

This example demonstrates the use of caching on a potentially costly operation.
Before invoking `computePiDecimal`, the abstraction looks for an entry in the `piDecimals` cache that matches the `precision` argument.
If an entry is found, the content in the cache is immediately returned to the caller, and the method is not invoked.
Otherwise, the method is invoked, and the cache is updated before returning the value.

CAUTION: You can also use the standard JSR-107 (JCache) annotations (such as javadoc:javax.cache.annotation.CacheResult[format=annotation]) transparently.
However, we strongly advise you to not mix and match the Spring Cache and JCache annotations.

If you do not add any specific cache library, Spring Boot auto-configures a xref:io/caching.adoc#io.caching.provider.simple[simple provider] that uses concurrent maps in memory.
When a cache is required (such as `piDecimals` in the preceding example), this provider creates it for you.
The simple provider is not really recommended for production usage, but it is great for getting started and making sure that you understand the features.
When you have made up your mind about the cache provider to use, please make sure to read its documentation to figure out how to configure the caches that your application uses.
Nearly all providers require you to explicitly configure every cache that you use in the application.
Some offer a way to customize the default caches defined by the configprop:spring.cache.cache-names[] property.

TIP: It is also possible to transparently {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-put[update] or {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-evict[evict] data from the cache.



[[io.caching.provider]]
== Supported Cache Providers

The cache abstraction does not provide an actual store and relies on abstraction materialized by the javadoc:org.springframework.cache.Cache[] and javadoc:org.springframework.cache.CacheManager[] interfaces.

If you have not defined a bean of type javadoc:org.springframework.cache.CacheManager[] or a javadoc:org.springframework.cache.interceptor.CacheResolver[] named `cacheResolver` (see javadoc:org.springframework.cache.annotation.CachingConfigurer[]), Spring Boot tries to detect the following providers (in the indicated order):

. xref:io/caching.adoc#io.caching.provider.generic[]
. xref:io/caching.adoc#io.caching.provider.jcache[] (EhCache 3, Hazelcast, Infinispan, and others)
. xref:io/caching.adoc#io.caching.provider.hazelcast[]
. xref:io/caching.adoc#io.caching.provider.infinispan[]
. xref:io/caching.adoc#io.caching.provider.couchbase[]
. xref:io/caching.adoc#io.caching.provider.redis[]
. xref:io/caching.adoc#io.caching.provider.caffeine[]
. xref:io/caching.adoc#io.caching.provider.cache2k[]
. xref:io/caching.adoc#io.caching.provider.simple[]

TIP: If the javadoc:org.springframework.cache.CacheManager[] is auto-configured by Spring Boot, it is possible to _force_ a particular cache provider by setting the configprop:spring.cache.type[] property.

TIP: Use the `spring-boot-starter-cache` starter to quickly add basic caching dependencies.
The starter brings in `spring-context-support`.
If you add dependencies manually, you must include `spring-context-support` in order to use the JCache or Caffeine support.

If the javadoc:org.springframework.cache.CacheManager[] is auto-configured by Spring Boot, you can further tune its configuration before it is fully initialized by exposing a bean that implements the javadoc:org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer[] interface.
The following example sets a flag to say that `null` values should not be passed down to the underlying map:

include-code::MyCacheManagerConfiguration[]

NOTE: In the preceding example, an auto-configured javadoc:org.springframework.cache.concurrent.ConcurrentMapCacheManager[] is expected.
If that is not the case (either you provided your own config or a different cache provider was auto-configured), the customizer is not invoked at all.
You can have as many customizers as you want, and you can also order them by using javadoc:org.springframework.core.annotation.Order[format=annotation] or javadoc:org.springframework.core.Ordered[].



[[io.caching.provider.generic]]
=== Generic

Generic caching is used if the context defines _at least_ one javadoc:org.springframework.cache.Cache[] bean.
A javadoc:org.springframework.cache.CacheManager[] wrapping all beans of that type is created.



[[io.caching.provider.jcache]]
=== JCache (JSR-107)

https://jcp.org/en/jsr/detail?id=107[JCache] is bootstrapped through the presence of a javadoc:javax.cache.spi.CachingProvider[] on the classpath (that is, a JSR-107 compliant caching library exists on the classpath), and the javadoc:org.springframework.cache.jcache.JCacheCacheManager[] is provided by the `spring-boot-starter-cache` starter.
Various compliant libraries are available, and Spring Boot provides dependency management for Ehcache 3, Hazelcast, and Infinispan.
Any other compliant library can be added as well.

It might happen that more than one provider is present, in which case the provider must be explicitly specified.
Even if the JSR-107 standard does not enforce a standardized way to define the location of the configuration file, Spring Boot does its best to accommodate setting a cache with implementation details, as shown in the following example:

[configprops,yaml]
----
    # Only necessary if more than one provider is present
	spring:
	  cache:
	    jcache:
	      provider: "com.example.MyCachingProvider"
	      config: "classpath:example.xml"
----

NOTE: When a cache library offers both a native implementation and JSR-107 support, Spring Boot prefers the JSR-107 support, so that the same features are available if you switch to a different JSR-107 implementation.

TIP: Spring Boot has xref:io/hazelcast.adoc[general support for Hazelcast].
If a single javadoc:com.hazelcast.core.HazelcastInstance[] is available, it is automatically reused for the javadoc:javax.cache.CacheManager[] as well, unless the configprop:spring.cache.jcache.config[] property is specified.

There are two ways to customize the underlying javadoc:javax.cache.CacheManager[]:

* Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property.
If a custom javadoc:javax.cache.configuration.Configuration[] bean is defined, it is used to customize them.
* javadoc:org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer[] beans are invoked with the reference of the javadoc:javax.cache.CacheManager[] for full customization.

TIP: If a standard javadoc:javax.cache.CacheManager[] bean is defined, it is wrapped automatically in an javadoc:org.springframework.cache.CacheManager[] implementation that the abstraction expects.
No further customization is applied to it.



[[io.caching.provider.hazelcast]]
=== Hazelcast

Spring Boot has xref:io/hazelcast.adoc[general support for Hazelcast].
If a javadoc:com.hazelcast.core.HazelcastInstance[] has been auto-configured and `com.hazelcast:hazelcast-spring` is on the classpath, it is automatically wrapped in a javadoc:org.springframework.cache.CacheManager[].

NOTE: Hazelcast can be used as a JCache compliant cache or as a Spring javadoc:org.springframework.cache.CacheManager[] compliant cache.
When setting configprop:spring.cache.type[] to `hazelcast`, Spring Boot will use the javadoc:org.springframework.cache.CacheManager[] based implementation.
If you want to use Hazelcast as a JCache compliant cache, set configprop:spring.cache.type[] to `jcache`.
If you have multiple JCache compliant cache providers and want to force the use of Hazelcast, you have to xref:io/caching.adoc#io.caching.provider.jcache[explicitly set the JCache provider].



[[io.caching.provider.infinispan]]
=== Infinispan

https://infinispan.org/[Infinispan] has no default configuration file location, so it must be specified explicitly.
Otherwise, the default bootstrap is used.

[configprops,yaml]
----
spring:
  cache:
    infinispan:
      config: "infinispan.xml"
----

Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property.
If a custom javadoc:org.infinispan.configuration.cache.ConfigurationBuilder[] bean is defined, it is used to customize the caches.

For more details, see https://infinispan.org/docs/stable/titles/spring/spring.html[the documentation].


[[io.caching.provider.couchbase]]
=== Couchbase

If Spring Data Couchbase is available and Couchbase is xref:data/nosql.adoc#data.nosql.couchbase[configured], a javadoc:org.springframework.data.couchbase.cache.CouchbaseCacheManager[] is auto-configured.
It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.couchbase.*` properties.
For instance, the following configuration creates `cache1` and `cache2` caches with an entry _expiration_ of 10 minutes:

[configprops,yaml]
----
spring:
  cache:
    cache-names: "cache1,cache2"
    couchbase:
      expiration: "10m"
----

If you need more control over the configuration, consider registering a javadoc:org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer[] bean.
The following example shows a customizer that configures a specific entry expiration for `cache1` and `cache2`:

include-code::MyCouchbaseCacheManagerConfiguration[]



[[io.caching.provider.redis]]
=== Redis

If https://redis.io/[Redis] is available and configured, a javadoc:org.springframework.data.redis.cache.RedisCacheManager[] is auto-configured.
It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.redis.*` properties.
For instance, the following configuration creates `cache1` and `cache2` caches with a _time to live_ of 10 minutes:

[configprops,yaml]
----
spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"
----

NOTE: By default, a key prefix is added so that, if two separate caches use the same key, Redis does not have overlapping keys and cannot return invalid values.
We strongly recommend keeping this setting enabled if you create your own javadoc:org.springframework.data.redis.cache.RedisCacheManager[].

TIP: You can take full control of the default configuration by adding a javadoc:org.springframework.data.redis.cache.RedisCacheConfiguration[] javadoc:org.springframework.context.annotation.Bean[format=annotation] of your own.
This can be useful if you need to customize the default serialization strategy.

If you need more control over the configuration, consider registering a javadoc:org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer[] bean.
The following example shows a customizer that configures a specific time to live for `cache1` and `cache2`:

include-code::MyRedisCacheManagerConfiguration[]



[[io.caching.provider.caffeine]]
=== Caffeine

https://github.com/ben-manes/caffeine[Caffeine] is a Java 8 rewrite of Guava's cache that supersedes support for Guava.
If Caffeine is present, a javadoc:org.springframework.cache.caffeine.CaffeineCacheManager[] (provided by the `spring-boot-starter-cache` starter) is auto-configured.
Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property and can be customized by one of the following (in the indicated order):

. A cache spec defined by `spring.cache.caffeine.spec`
. A javadoc:com.github.benmanes.caffeine.cache.CaffeineSpec[] bean is defined
. A javadoc:com.github.benmanes.caffeine.cache.Caffeine[] bean is defined

For instance, the following configuration creates `cache1` and `cache2` caches with a maximum size of 500 and a _time to live_ of 10 minutes

[configprops,yaml]
----
spring:
  cache:
    cache-names: "cache1,cache2"
    caffeine:
      spec: "maximumSize=500,expireAfterAccess=600s"
----

If a javadoc:com.github.benmanes.caffeine.cache.CacheLoader[] bean is defined, it is automatically associated to the javadoc:org.springframework.cache.caffeine.CaffeineCacheManager[].
Since the javadoc:com.github.benmanes.caffeine.cache.CacheLoader[] is going to be associated with _all_ caches managed by the cache manager, it must be defined as `CacheLoader<Object, Object>`.
The auto-configuration ignores any other generic type.



[[io.caching.provider.cache2k]]
=== Cache2k

https://cache2k.org/[Cache2k] is an in-memory cache.
If the Cache2k spring integration is present, a `SpringCache2kCacheManager` is auto-configured.

Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property.
Cache defaults can be customized using a javadoc:org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer[] bean.
The following example shows a customizer that configures the capacity of the cache to 200 entries, with an expiration of 5 minutes:

include-code::MyCache2kDefaultsConfiguration[]



[[io.caching.provider.simple]]
=== Simple

If none of the other providers can be found, a simple implementation using a javadoc:java.util.concurrent.ConcurrentHashMap[] as the cache store is configured.
This is the default if no caching library is present in your application.
By default, caches are created as needed, but you can restrict the list of available caches by setting the `cache-names` property.
For instance, if you want only `cache1` and `cache2` caches, set the `cache-names` property as follows:

[configprops,yaml]
----
spring:
  cache:
    cache-names: "cache1,cache2"
----

If you do so and your application uses a cache not listed, then it fails at runtime when the cache is needed, but not on startup.
This is similar to the way the "real" cache providers behave if you use an undeclared cache.



[[io.caching.provider.none]]
=== None

If you need to use a no-op cache rather than the auto-configured cache manager in a certain environment, set the cache type to `none`, as shown in the following example:

[configprops,yaml]
----
spring:
  cache:
    type: "none"
----



[[io.caching.testing]]
== Testing

It is generally useful to use a no-op implementation when running a test suite.
This section lists a number of strategies that are useful for tests.

When a custom javadoc:org.springframework.cache.CacheManager[] is defined, the best option is to make sure that caching configuration is defined in an isolated javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.
Doing so makes sure that caching is not required by slice tests.
For tests that enable a full context, such as javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation], an explicit configuration overriding the regular configuration is required.

If caching is auto-configured, more options are available.
Slice tests are annotated with javadoc:org.springframework.boot.test.autoconfigure.core.AutoConfigureCache[format=annotation], which replaces the auto-configured javadoc:org.springframework.cache.CacheManager[] by a no-op implementation.
Integration tests can also benefit from this feature by annotate the relevant test class as follows:

include-code::MyIntegrationTests[]

Another option is to force a no-op implementation for the auto-configured javadoc:org.springframework.cache.CacheManager[]:

[configprops,yaml]
----
spring:
  cache:
    type: "none"
----
