https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#io.caching
Spring Framework 支持透明地为应用程序添加缓存。其核心抽象将缓存应用于方法,从而根据缓存中的信息减少执行次数。缓存逻辑是透明地应用的,对调用者没有任何干扰。只要通过 @EnableCaching
注解启用缓存支持,Spring Boot 就会自动配置缓存基础结构。
简而言之,要为服务的操作添加缓存,请将其相关注解添加到该方法的上面,如下所示:
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class MyMathService {
@Cacheable("piDecimals")
public int computePiDecimal(int precision) {
...
}
}
此示例演示了如何在可能昂贵的操作上使用缓存。在调用 computePiDecimal
之前,抽象会在 piDecimals
缓存中查找匹配的条目。如果找到条目,缓存中的内容将立即返回给调用方,并且不会调用该方法。否则,将调用该方法,并在返回值之前更新缓存。
注意:您可以透明地使用标准的 JSR-107(JCache)注解(如 @CacheResult
)。但是,强烈建议您不要混合使用 Spring Cache 和 JCache 注解。
如果你没有添加任何特定的缓存库,Spring Boot 会自动配置一个使用内存中并发映射的简单提供程序。当需要缓存时(如前一个示例中的 piDecimals
),此提供程序会为你创建它。简单提供程序不建议用于生产用途,但它非常适合入门并确保你了解这些功能。几乎所有的提供程序都需要明确配置应用程序中使用的每个缓存。一些提供程序提供了一种自定义由 spring.cache.cache-names
属性定义的默认缓存的方式。
提示:还可以透明地更新或驱逐缓存中的数据。
支持的缓存提供程序(Providers)
缓存抽象不提供实际的存储,而是依赖于由 org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
接口实现的抽象。
如果没有定义类型为 CacheManager
的 bean 或名为 cacheResolver
的 CacheResolver,Spring Boot 将尝试按以下顺序检测以下提供程序:
- Generic
- JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, 其它)
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Cache2k
- Simple
此外,Spring Boot for Apache Geode 还提供了自动配置功能,以使用 Apache Geode 作为缓存提供程序。
提示:如果 CacheManager
是由 Spring Boot 自动配置的,则可以通过设置 spring.cache.type
属性来强制使用特定的缓存提供程序。如果您需要在某些环境(例如测试)中使用,请使用此属性。
提示:使用 spring-boot-starter-cache
“Starter” 可以快速添加基本的缓存依赖项。该 Starter 会引入 spring-context-support
。如果手动添加依赖项,则必须包含 spring-context-support
才能使用 JCache 或 Caffeine 支持。
如果 CacheManager
是由 Spring Boot 自动配置的,可以在其完全初始化之前通过公开实现 CacheManagerCustomizer
接口的 bean 来进一步调整其配置。以下示例设置了一个标志,表示不应将 null
值传递给基础映射:
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return (cacheManager) -> cacheManager.setAllowNullValues(false);
}
}
注意:在前一个示例中,期望自动配置一个 ConcurrentMapCacheManager
。如果不是这种情况(要么你提供了自己的配置,要么自动配置了不同的缓存提供程序),则不会调用自定义程序。你可以根据需要拥有任意数量的自定义程序,还可以使用 @Order
或 Ordered
对其进行排序。
Generic
如果上下文中定义了至少一个 org.springframework.cache.Cache
bean,则使用通用缓存。将创建一个包装该类型所有 bean 的 CacheManager
。
JCache (JSR-107)
JCache 是通过在类路径上存在 javax.cache.spi.CachingProvider
(即类路径上存在符合 JSR-107 规范的缓存库)来启动的,而 JCacheCacheManager
是由 spring-boot-starter-cache
“Starter” 提供的。有多种符合规范的库可供选择,Spring Boot 为 Ehcache 3、Hazelcast 和 Infinispan 提供了依赖管理。还可以添加任何其它符合规范的库。
可能会出现多个提供程序的情况,在这种情况下,必须明确指定提供程序。即使 JSR-107 标准不强制执行定义配置文件位置的标准化方式,Spring Boot 也尽其所能来容纳使用实现细节的缓存设置,如下所示:
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.example.MyCachingProvider
spring.cache.jcache.config=classpath:example.xml
注意:当缓存库同时提供原生实现和 JSR-107 支持时,Spring Boot 更倾向于使用 JSR-107 支持,这样如果切换到不同的 JSR-107 实现,将提供相同的功能。
提示:Spring Boot 对 Hazelcast 具有一般支持。如果单个 HazelcastInstance
可用,则会自动将其重用于 CacheManager
,除非指定了 spring.cache.jcache.config
属性。
有两种方法可以自定义底层的 javax.cache.cacheManager
:
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存。如果定义了自定义的 javax.cache.configuration.Configuration
bean,则使用它来定制它们。
将调用 org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean,并传入 CacheManager
的引用以进行完整定制。
提示:如果定义了标准的 javax.cache.CacheManager
bean,则会自动将其包装在抽象所期望的 org.springframework.cache.CacheManager
实现中。不会对其应用进一步的定制。
Hazelcast
Spring Boot 对 Hazelcast 具有一般支持。如果已自动配置 HazelcastInstance
,并且 com.hazelcast:hazelcast-spring
在类路径上,则会自动将其包装在 CacheManager
中。
注意:
Hazelcast 可以作为符合 JCache 规范的缓存或符合 Spring CacheManager
规范的缓存使用。当将 spring.cache.type
设置为 hazelcast
时,Spring Boot 将使用基于 CacheManager
的实现。如果想将 Hazelcast 用作符合 JCache 规范的缓存,请将 spring.cache.type
设置为 jcache
。如果有多个符合 JCache 规范的缓存提供程序,并且想强制使用 Hazelcast,则必须明确设置 JCache 提供程序。
Infinispan
Infinispan 没有默认的配置文件位置,因此必须明确指定。否则,将使用默认引导程序。
spring.cache.infinispan.config=infinispan.xml
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存。如果定义了自定义的 ConfigurationBuilder
bean,则用于定制缓存。
为了与 Spring Boot 的 Jakarta EE 9 基线兼容,必须使用 Infinispan 的 -jakarta
模块。对于每个带有 -jakarta
变体的模块,必须使用变体代替标准模块。例如,必须使用 infinispan-core-jakarta
和 infinispan-commons-jakarta
代替 infinispan-core
和 infinispan-commons
。
Couchbase
如果 Spring Data Couchbase 可用并配置了 Couchbase,则会自动配置 CouchbaseCacheManager
。可以通过设置 spring.cache.cache-names
属性在启动时创建其它缓存,并使用 spring.cache.couchbase.*
属性配置缓存的默认值。例如,以下配置将创建具有 10
分钟条目过期时间的 cache1
和 cache2
缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
如果需要更多对配置的控制权,请考虑注册一个 CouchbaseCacheManagerBuilderCustomizer
bean。以下示例显示了一个自定义程序,它为 cache1
和 cache2
配置了特定的条目过期时间:
import java.time.Duration;
import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;
@Configuration(proxyBeanMethods = false)
public class MyCouchbaseCacheManagerConfiguration {
@Bean
public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1", CouchbaseCacheConfiguration
.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2", CouchbaseCacheConfiguration
.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));
}
}
Redis
如果 Redis 可用并已配置,将自动配置 RedisCacheManager
。可以通过设置 spring.cache.cache-names
属性在启动时创建其它缓存,并使用 spring.cache.redis.*
属性配置缓存的默认值。例如,以下配置将创建具有 10
分钟生存时间的 cache1
和 cache2
缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=10m
注意:默认情况下,会添加一个键前缀,以便如果两个独立的缓存使用相同的键,Redis 不会有重叠的键,也无法返回无效的值。如果创建自己的 RedisCacheManager
,强烈建议启用此设置。
提示:可以通过添加自己的 RedisCacheConfiguration
@Bean
来完全控制默认配置。如果需要自定义默认的序列化策略,这可能会很有用。
如果需要更多对配置的控制权,请考虑注册一个 RedisCacheManagerBuilderCustomizer
bean。以下示例显示了一个自定义程序,它为 cache1
和 cache2
配置了特定的生存时间:
import java.time.Duration;
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
@Configuration(proxyBeanMethods = false)
public class MyRedisCacheManagerConfiguration {
@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));
}
}
Caffeine
Caffeine 是 Guava 缓存的 Java 8 重写版本,它取代了对 Guava 的支持。如果存在 Caffeine,则会自动配置 CaffeineCacheManager
(由 spring-boot-starter-cache
“Starter” 提供)。可以通过设置 spring.cache.cache-names
属性在启动时创建缓存,并可以通过以下方式之一进行自定义(按指示的顺序):
- 由
spring.cache.caffeine.spec
定义的缓存规范 - 定义了
com.github.benmanes.caffeine.cache.CaffeineSpec
bean - 定义了
com.github.benmanes.caffeine.cache.Caffeine
bean
例如,以下配置创建了两个缓存 cache1
和 cache2
,它们的最大大小为 500
,生存时间为 10
分钟:
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
如果定义了 com.github.benmanes.caffeine.cache.CacheLoader
bean,则它会自动与 CaffeineCacheManager
关联。由于 CacheLoader
将与缓存管理器管理的所有缓存关联,因此必须将其定义为 CacheLoader<Object, Object>
。自动配置将忽略任何其它泛型类型。
Cache2k
Cache2k 是一个内存缓存。如果 Cache2k 的 Spring 集成存在,则会自动配置 SpringCache2kCacheManager
。
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存。可以使用 Cache2kBuilderCustomizer
bean 自定义缓存的默认值。以下示例显示了一个自定义程序,它将缓存的容量配置为 200
个条目,过期时间为 5
分钟:
import java.util.concurrent.TimeUnit;
import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyCache2kDefaultsConfiguration {
@Bean
public Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {
return (builder) -> builder.entryCapacity(200)
.expireAfterWrite(5, TimeUnit.MINUTES);
}
}
Simple
如果找不到其它提供者,则会配置一个使用 ConcurrentHashMap
作为缓存存储的简单实现。如果在你的应用程序中没有缓存库,则这是默认设置。默认情况下,会按需创建缓存,但可以通过设置 cache-names
属性来限制可用缓存的列表。例如,如果只需要 cache1
和 cache2
缓存,请按如下方式设置 cache-names
属性:
spring.cache.cache-names=cache1,cache2
如果你这样做,并且你的应用程序使用了未列出的缓存,那么当需要缓存时,它会在运行时失败,而不是在启动时失败。这与你使用未声明的缓存时“真正”的缓存提供者的行为类似。
None
当配置中存在 @EnableCaching
时,也需要一个合适的缓存配置。如果有自定义的 CacheManager
,请考虑将其定义在一个单独的 @Configuration
类中,以便在必要时可以覆盖它。None 使用了一个在测试中很有用的无操作(no-op)实现,切片测试默认通过 @AutoConfigureCache
使用它。
如果需要在特定环境中使用无操作缓存而不是自动配置的缓存管理器,请将缓存类型设置为 none
,如下所示:
spring.cache.type=none