31. Caching
Spring 框架提供了对向应用程序透明添加缓存的支持。从本质上讲,抽象将缓存应用于方法,从而基于缓存中可用的信息减少了执行次数。缓存逻辑是透明应用的,不会对调用者造成任何干扰。只要通过@EnableCaching
Comments 启用了缓存支持,Spring Boot 就会自动配置缓存基础结构。
Note
查看 Spring 框架参考的relevant section以获得更多详细信息。
简而言之,向服务的操作中添加缓存就像向其方法中添加相关 Comments 一样容易:
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Component;
@Component
public class MathService {
@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// ...
}
}
本示例说明了在可能耗资巨大的操作上使用缓存的方法。在调用computePiDecimal
之前,抽象将在piDecimals
缓存中寻找与i
参数匹配的条目。如果找到条目,则将高速缓存中的内容立即返回给调用方,并且不会调用该方法。否则,将在返回值之前调用该方法并更新缓存。
Note
您还可以透明地使用标准 JSR-107(JCache)Comments(例如@CacheResult
)。但是,我们强烈建议您不要混搭它们。
如果您不添加任何特定的缓存库,Spring Boot 将自动配置一个使用内存中并发 Map 的Simple provider。当需要缓存时(即上面的示例中的piDecimals
),该提供程序将为您即时创建缓存。实际上,不建议将简单的提供程序用于生产用途,但是它对于 Starter 并确保您了解功能非常有用。确定要使用的缓存提供程序后,请确保阅读其文档,以了解如何配置应用程序使用的缓存。实际上,所有提供程序都要求您显式配置在应用程序中使用的每个缓存。有些提供了一种自定义spring.cache.cache-names
属性定义的默认缓存的方法。
Note
如果您将高速缓存基础结构与不基于接口的 bean 一起使用,请确保启用@EnableCaching
的proxyTargetClass
属性。
31.1 支持的缓存提供程序
缓存抽象不提供实际的存储,而是依赖于org.springframework.cache.Cache
和org.springframework.cache.CacheManager
接口实现的抽象。
如果尚未定义类型CacheManager
或CacheResolver
名为cacheResolver
(请参见CachingConfigurer
),则 Spring Boot 尝试检测以下提供程序(按此 Sequences):
-
JCache (JSR-107)(EhCache 3,Hazelcast,Infinispan 等)
-
Guava (deprecated)
Tip
也可以通过spring.cache.type
属性来强制使用缓存提供程序。如果您需要在特定环境(例如测试)中完全禁用缓存,请使用此属性。
Tip
使用spring-boot-starter-cache
“Starter”快速添加基本的缓存依赖项。Starter 工具提供spring-context-support
:如果要手动添加依赖项,则必须包含spring-context-support
才能使用 JCache,EhCache 2.x 或 Guava 支持。
如果CacheManager
是由 Spring Boot 自动配置的,则可以通过公开实现CacheManagerCustomizer
接口的 bean,在完全初始化之前进一步调整其配置。以下代码设置了一个标志,指示应将空值向下传递到基础 Map。
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}
Note
在上面的示例中,应该使用自动配置的ConcurrentMapCacheManager
。如果不是这种情况(您提供了自己的配置,或者自动配置了其他缓存提供程序),则根本不会调用定制程序。您可以根据需要拥有任意数量的定制程序,也可以使用@Order
或Ordered
像往常一样 Order 它们。
31.1.1 Generic
如果上下文至少定义了一个org.springframework.cache.Cache
bean,则使用通用缓存。创建一个CacheManager
包装该类型的所有 bean。
31.1.2 JCache(JSR-107)
通过 Classpath 上的javax.cache.spi.CachingProvider
(即符合 JSR-107 的缓存库)和spring-boot-starter-cache
'Starter'提供的JCacheCacheManager
引导 JCache。这里有各种兼容的库,Spring Boot 为 Ehcache 3,Hazelcast 和 Infinispan 提供了依赖 Management。也可以添加任何其他兼容的库。
可能会出现多个提供者,在这种情况下,必须明确指定提供者。即使 JSR-107 标准没有强制采用标准化的方式来定义配置文件的位置,Spring Boot 也会尽最大努力适应实现细节。
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml
Note
由于缓存库可能同时提供本机实现和 JSR-107 支持,因此 Spring Boot 会更喜欢 JSR-107 支持,以便在切换到其他 JSR-107 实现时可以使用相同的功能。
Tip
Spring Boot 具有对 Hazelcast 的常规支持。如果单个HazelcastInstance
可用,则除非指定spring.cache.jcache.config
属性,否则它也会自动重用于CacheManager
。
有几种方法可以自定义基础javax.cache.cacheManager
:
-
可以在启动时通过
spring.cache.cache-names
属性创建缓存。如果定义了自定义javax.cache.configuration.Configuration
bean,则将其用于自定义它们。 -
org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean 与CacheManager
的引用一起调用以进行完全自定义。
Tip
如果定义了标准的javax.cache.CacheManager
bean,它将自动包装在抽象期望的org.springframework.cache.CacheManager
实现中。不再对其应用定制。
31.1.3 EhCache 2.x
如果可以在 Classpath 的根目录下找到名为ehcache.xml
的文件,则使用 EhCache2.x。如果是 EhCache 2.x,则存在spring-boot-starter-cache
'Starter'提供的EhCacheCacheManager
以及此类文件,它用于引导缓存 Management 器。也可以使用以下方法提供备用配置文件:
spring.cache.ehcache.config=classpath:config/another-config.xml
31.1.4 Hazelcast
Spring Boot 具有对 Hazelcast 的常规支持。如果已自动配置HazelcastInstance
,则会自动将其包装在CacheManager
中。
31.1.5 Infinispan
Infinispan 没有默认配置文件位置,因此必须明确指定(或使用默认引导程序)。
spring.cache.infinispan.config=infinispan.xml
可以在启动时通过spring.cache.cache-names
属性创建缓存。如果定义了自定义ConfigurationBuilder
bean,则将其用于自定义它们。
Note
Spring Boot 对 Infinispan 的支持仅限于嵌入式模式,并且非常基础。如果您需要更多选项,则应该使用 Infinispan Spring Boot 官方启动器,请查看the documentation以获取更多详细信息。
31.1.6 Couchbase
如果 Couchbase JavaClient 端和couchbase-spring-cache
实现可用并且 Couchbase 为configured,则会自动配置CouchbaseCacheManager
。也可以在启动时使用spring.cache.cache-names
属性创建其他缓存。这些将在自动配置的Bucket
上运行。您也可以*使用定制程序在另一个Bucket
上创建其他缓存:假设您需要在“主” Bucket
(foo
和bar
)上创建两个缓存,并在another
Bucket
上创建一个自定义生存时间为 2 秒的biz
缓存。首先,您可以简单地通过配置创建两个第一个缓存:
spring.cache.cache-names=foo,bar
然后定义此额外的@Configuration
以配置额外的Bucket
和biz
缓存:
@Configuration
public class CouchbaseCacheConfiguration {
private final Cluster cluster;
public CouchbaseCacheConfiguration(Cluster cluster) {
this.cluster = cluster;
}
@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
}
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
return c -> {
c.prepareCache("biz", CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
};
}
}
此示例配置重用了通过自动配置创建的Cluster
。
31.1.7 Redis
如果 Redis 可用并已配置,则RedisCacheManager
是自动配置的。也可以使用spring.cache.cache-names
属性在启动时创建其他缓存。
Note
默认情况下,添加了键前缀以防止如果两个单独的缓存使用相同的键,则 Redis 将具有重叠的键并可能返回无效值。如果您创建自己的RedisCacheManager
,强烈建议保留此设置。
31.1.8 Caffeine
Caffeine 是 Java 8 对 Guava 缓存的重写,它将取代 Spring Boot 2.0 中对 Guava 的支持。如果存在 Caffeine,则会自动配置CaffeineCacheManager
(由spring-boot-starter-cache
“Starter”提供)。缓存可以在启动时使用spring.cache.cache-names
属性创建,并可以通过以下方式之一自定义(按此 Sequences):
-
spring.cache.caffeine.spec
定义的缓存规范 -
定义了一个
com.github.benmanes.caffeine.cache.CaffeineSpec
bean -
定义了一个
com.github.benmanes.caffeine.cache.Caffeine
bean
例如,以下配置创建一个foo
和bar
缓存,最大大小为 500,并且生存时间为 10 分钟
spring.cache.cache-names=foo,bar
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
此外,如果定义了com.github.benmanes.caffeine.cache.CacheLoader
bean,它将自动与CaffeineCacheManager
关联。由于CacheLoader
将与由缓存 Management 器 Management 的所有缓存相关联,因此必须将其定义为CacheLoader<Object, Object>
。自动配置将忽略任何其他通用类型。
31.1.9Guava(已弃用)
如果存在 Guava,则会自动配置GuavaCacheManager
。缓存可以在启动时使用spring.cache.cache-names
属性创建,并可以由以下其中一项自定义(按此 Sequences):
-
spring.cache.guava.spec
定义的缓存规范 -
定义了一个
com.google.common.cache.CacheBuilderSpec
bean -
定义了一个
com.google.common.cache.CacheBuilder
bean
例如,以下配置创建一个foo
和bar
缓存,最大大小为 500,并且生存时间为 10 分钟
spring.cache.cache-names=foo,bar
spring.cache.guava.spec=maximumSize=500,expireAfterAccess=600s
此外,如果定义了com.google.common.cache.CacheLoader
bean,它将自动与GuavaCacheManager
关联。由于CacheLoader
将与由缓存 Management 器 Management 的所有缓存相关联,因此必须将其定义为CacheLoader<Object, Object>
。自动配置将忽略任何其他通用类型。
31.1.10 Simple
如果找不到其他提供者,则配置使用ConcurrentHashMap
作为缓存存储的简单实现。如果您的应用程序中不存在任何缓存库,则这是默认设置。默认情况下会即时创建缓存,但是您可以使用cache-names
属性来限制可用缓存的列表。例如,如果只需要foo
和bar
缓存:
spring.cache.cache-names=foo,bar
如果执行此操作,并且您的应用程序使用了未列出的缓存,则它将在需要缓存时在运行时失败,而不是在启动时失败。这类似于使用未声明的缓存时“实际”缓存提供程序的行为。
31.1.11 None
当您的配置中包含@EnableCaching
时,也需要合适的缓存配置。如果您需要在某些环境中完全禁用缓存,请强制将缓存类型设置为none
以使用无操作实现:
spring.cache.type=none