Caching

Spring Framework 提供对透明地将缓存添加到应用程序的支持。在它的核心,这个抽象对方法应用了缓存,因此基于缓存中可用信息减少执行次数。缓存逻辑以透明的方式应用,没有任何对调用者的干扰。只要使用 @EnableCaching 注解启用缓存支持,Spring Boot 就能自动配置缓存基础设施。

有关更多详细信息,请查阅 Spring Framework 参考的 {url-spring-framework-docs}/integration/cache.html[相关部分]。

简而言之,若要向服务的某个操作添加缓存,请对其方法添加相关注释,如下例所示: include-code::MyMathService[] 本示例说明了在潜在成本高昂的操作上使用缓存的方法。在调用 computePiDecimal 之前,抽象将查找 piDecimals 缓存中与 i 参数匹配的条目。如果找到条目,缓存中的内容将立即返回给调用者,且该方法不会被调用。否则,将调用该方法,且在返回该值之前先对缓存进行更新。

你也可以透明地使用标准的 JSR-107(JCache)注解(例如 @CacheResult)。但是,我们强烈建议你不要混合使用 Spring Cache 和 JCache 注解。

如果你没有添加任何特定的缓存库,Spring Boot 会自动配置一个使用内存中的并发映射的 simple provider。当需要使用缓存时(例如在前面的示例中的 piDecimals),此提供程序会为你创建缓存。简单的提供程序并不适合用于生产用途,但是非常适合于入门和确保你了解这些特性。当你决定要使用的缓存提供程序时,请务必仔细阅读其文档以了解如何配置你的应用程序使用的缓存。几乎所有提供程序都要求你明确配置应用程序中使用的每个缓存。有些提供程序提供自定义由 configprop:spring.cache.cache-names[] 属性定义的默认缓存的方法。

还可以透明地将数据从缓存中 {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-put[更新] 或 {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-evict[逐出]。

Supported Cache Providers

缓存抽象不提供实际的存储,它依赖 org.springframework.cache.Cacheorg.springframework.cache.CacheManager 接口实现的抽象。

如果你尚未定义 CacheManager 类型的 Bean 或名为 cacheResolverCacheResolver(请参见 {url-spring-framework-javadoc}/org/springframework/cache/annotation/CachingConfigurer.html[CachingConfigurer]),Spring Boot 将尝试按指示的顺序检测以下提供程序。

  1. Generic

  2. JCache (JSR-107)(EhCache 3、Hazelcast、Infinispan 等)

  3. Hazelcast

  4. Infinispan

  5. Couchbase

  6. Redis

  7. Caffeine

  8. Cache2k

  9. Simple

此外,{url-spring-boot-for-apache-geode-site}[Spring Boot for Apache Geode] 提供 {url-spring-boot-for-apache-geode-docs}#geode-caching-provider[用于将 Apache Geode 用作缓存提供程序的自动配置]。

如果 Spring Boot 自动配置 CacheManager,那么可以通过设置 configprop:spring.cache.type[] 属性来 force 特定的缓存提供程序。如果你需要在特定环境(例如测试)中 use no-op caches,请使用此属性。

使用 spring-boot-starter-cache “Starter” 以快速添加基本的缓存依赖项。该 starter 会引入 spring-context-support。如果你手动添加依赖项,那么为了使用 JCache 或 Caffeine 支持,你必须包含 spring-context-support

如果 Spring Boot 自动配置 CacheManager,则可以在完全初始化之前通过公开一个实现了 CacheManagerCustomizer 接口的 Bean 来进一步调整其配置。以下示例设置一个标记来说 null 值不应传递到底层映射:

在前面的示例中,会预期自动配置 ConcurrentMapCacheManager。如果不是这种情况(或者是你提供了自己的配置,或者自动配置了其他缓存提供程序),那么将不会调用该定制器。你可以随意使用任意数量的定制器,还可以使用 @OrderOrdered 对其进行排序。

Generic

如果上下文定义 at leastorg.springframework.cache.Cache Bean,则使用通用缓存。将创建包含该类型的所有 Bean 的 CacheManager

JCache (JSR-107)

通过类路径中存在 javax.cache.spi.CachingProviderJCache 进行引导(也就是说,类路径中存在 JSR-107 兼容缓存库),而 JCacheCacheManagerspring-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"
	      config: "classpath:example.xml"

当缓存库既提供本机实现又支持 JSR-107 时,Spring Boot 更喜欢使用 JSR-107 支持,以便在你切换到不同的 JSR-107 实现时可以使用相同的特性。

Spring Boot 拥有 general support for Hazelcast。如果一个 HazelcastInstance 可用,它也会自动用于 CacheManager,除非指定了 configprop:spring.cache.jcache.config[] 属性。

有两种方法可以自定义基础 javax.cache.cacheManager

  • 可以通过设置 configprop: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 拥有 general support for Hazelcast。如果已自动配置 HazelcastInstancecom.hazelcast:hazelcast-spring 在类路径上,则自动将其包装在 CacheManager 中。

Hazelcast 可用作 JCache 兼容缓存或 Spring CacheManager 兼容缓存。将 configprop:spring.cache.type[] 设置为 hazelcast 时,Spring Boot 将使用基于 CacheManager 的实现。如果想要使用 Hazelcast 作为 JCache 兼容缓存,请将 configprop:spring.cache.type[] 设置为 jcache。如果你有多个 JCache 兼容缓存提供者,并且想要强制使用 Hazelcast,则必须 explicitly set the JCache provider

Infinispan

Infinispan 没有默认配置文件位置,因此必须明确指定。否则,将使用默认引导程序。

spring:
  cache:
    infinispan:
      config: "infinispan.xml"

可以通过设置 configprop:spring.cache.cache-names[] 属性在启动时创建缓存。如果定义了自定义 ConfigurationBuilder Bean,则使用它来自定义缓存。

为了兼容 Spring Boot 的 Jakarta EE 9 基线,必须使用 Infinispan 的 -jakarta 模块。对于具有 -jakarta 变体的每个模块,必须使用变体来代替标准模块。例如,必须分别使用 infinispan-core-jakartainfinispan-commons-jakarta 来代替 infinispan-coreinfinispan-commons

Couchbase

如果 Spring Data Couchbase 可用且 Couchbase 是 configured,则会自动配置 CouchbaseCacheManager。可以通过设置 configprop:spring.cache.cache-names[] 属性创建附加缓存,可使用 spring.cache.couchbase.* 属性配置缓存默认值。例如,以下配置使用 10 分钟的条目 expiration 创建 cache1cache2 缓存:

spring:
  cache:
    cache-names: "cache1,cache2"
    couchbase:
      expiration: "10m"

如果你需要对配置进行更多控制,可以考虑注册 CouchbaseCacheManagerBuilderCustomizer Bean。以下示例显示了一个自定义程序,它为 cache1cache2 配置了一个特定的条目过期时间:

Redis

如果 Redis 可用且已配置,则会自动配置 RedisCacheManager。可以通过设置 configprop:spring.cache.cache-names[] 属性创建附加缓存,可使用 spring.cache.redis.* 属性配置缓存默认值。例如,以下配置使用 10 分钟的 time to live 创建 cache1cache2 缓存:

spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"

默认情况下,会添加一个键前缀,以便如果两个单独的缓存使用相同的键,Redis 不会有重叠的键并且无法返回无效的值。如果你创建自己的 RedisCacheManager,我们强烈建议保持此设置处于启用状态。

你可以通过添加自己的 RedisCacheConfiguration @Bean 来完全控制默认配置。如果你需要自定义默认序列化策略,这会很有用。

如果你需要对配置进行更多控制,可以考虑注册 RedisCacheManagerBuilderCustomizer Bean。以下示例显示了一个自定义程序,它为 cache1cache2 配置了一个特定的生存时间:

Caffeine

Caffeine是Guava缓存的Java8重写,它取代了对Guava的支持。如果Caffeine存在,将`CaffeineCacheManager`(由`spring-boot-starter-cache`"`Starter`"提供)自动配置。可以通过设置configprop:spring.cache.cache-names[]属性来在启动时创建缓存,并且可以通过以下方式之一(按指示的顺序)进行自定义:

  1. 由`spring.cache.caffeine.spec`定义的缓存规范

  2. 定义了`com.github.benmanes.caffeine.cache.CaffeineSpec`bean

  3. 定义了`com.github.benmanes.caffeine.cache.Caffeine`bean

例如,下列配置使用最大大小为500和_time to live_为10分钟的创建`cache1`和`cache2`缓存:

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

如果定义了`com.github.benmanes.caffeine.cache.CacheLoader`bean,则它会自动与`CaffeineCacheManager`关联。由于`CacheLoader`将与缓存管理器管理的_all_缓存相关联,因此必须将其定义为`CacheLoader<Object, Object>`。自动配置忽略任何其他通用类型。

Cache2k

Cache2k是一个内存缓存。如果存在Cache2k Spring集成,则自动配置`SpringCache2kCacheManager`。

可以通过设置configprop:spring.cache.cache-names[]属性来在启动时创建缓存。可以使用`Cache2kBuilderCustomizer`bean自定义缓存默认值。以下示例显示了一个定制器,它将缓存的容量配置为200个条目,到期时间为5分钟:

Simple

如果找不到任何其他提供程序,则配置使用`ConcurrentHashMap`作为缓存存储的简单实现。如果应用程序中不存在缓存库,则这是默认设置。默认情况下,会根据需要创建缓存,但是你可以通过设置`cache-names`属性来限制可用缓存的列表。例如,如果你只想保留`cache1`和`cache2`缓存,请按如下方式设置`cache-names`属性:

spring:
  cache:
    cache-names: "cache1,cache2"

如果你这样做并且你的应用程序使用了未列出的缓存,那么在需要缓存时(而不是在启动时)运行时会失败。这类似于在你使用未申报的缓存时,“实际”缓存提供程序的行为方式。

None

当`@EnableCaching`存在于你的配置中时,也需要适当的缓存配置。如果你有自定义`CacheManager`,请考虑在单独的`@Configuration`类中对其进行定义,以便在必要时可以覆盖它。None使用无操作实现,这在测试中很有用,切片测试通过`@AutoConfigureCache`默认使用它。

如果你需要在特定环境中使用无操作缓存,而不是自动配置的缓存管理器,请将缓存类型设置为`none`,如下例所示:

spring:
  cache:
    type: "none"