快取
Spring Framework 支援透明地嚮應用程式新增快取。其核心是,該抽象將快取應用於方法,從而根據快取中可用的資訊減少執行次數。快取邏輯是透明應用的,不會對呼叫者造成任何干擾。只要透過使用 @EnableCaching 註解啟用快取支援,Spring Boot 就會自動配置快取基礎設施。
| 有關更多詳細資訊,請查閱 Spring Framework 參考的 相關部分。 |
簡而言之,要向服務的操作新增快取,請在其方法上新增相關注解,如以下示例所示
-
Java
-
Kotlin
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class MyMathService {
@Cacheable("piDecimals")
public int computePiDecimal(int precision) {
...
}
}
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Component
@Component
class MyMathService {
@Cacheable("piDecimals")
fun computePiDecimal(precision: Int): Int {
...
}
}
此示例演示了在可能開銷很大的操作上使用快取。在呼叫 computePiDecimal 之前,抽象會在 piDecimals 快取中查詢與 precision 引數匹配的條目。如果找到條目,快取中的內容會立即返回給呼叫者,並且不會呼叫該方法。否則,將呼叫該方法,並在返回該值之前更新快取。
您還可以透明地使用標準 JSR-107 (JCache) 註解(例如 @CacheResult)。但是,我們強烈建議您不要混用 Spring Cache 和 JCache 註解。 |
如果您不新增任何特定的快取庫,Spring Boot 會自動配置一個使用記憶體中併發對映的簡單提供程式。當需要快取(例如前面示例中的 piDecimals)時,此提供程式會為您建立它。簡單提供程式不真正推薦用於生產用途,但它非常適合入門並確保您理解這些功能。當您決定要使用的快取提供程式時,請務必閱讀其文件以瞭解如何配置應用程式使用的快取。幾乎所有提供程式都要求您明確配置應用程式中使用的每個快取。有些提供了一種透過 spring.cache.cache-names 屬性自定義預設快取的方法。
支援的快取提供程式
快取抽象不提供實際儲存,而是依賴於由 Cache 和 CacheManager 介面實現的抽象。
如果您尚未定義型別為 CacheManager 的 bean 或名為 cacheResolver 的 CacheResolver(請參閱 CachingConfigurer),Spring Boot 會嘗試檢測以下提供程式(按所示順序)
-
JCache (JSR-107)(EhCache 3、Hazelcast、Infinispan 及其他)
如果 CacheManager 由 Spring Boot 自動配置,則可以透過設定 spring.cache.type 屬性來 強制 指定特定的快取提供程式。如果您需要在某些環境(例如測試)中使用無操作快取,請使用此屬性。 |
使用 spring-boot-starter-cache 啟動器可以快速新增基本的快取依賴項。該啟動器引入了 spring-context-support。如果您手動新增依賴項,則必須包含 spring-context-support 才能使用 JCache 或 Caffeine 支援。 |
如果 CacheManager 由 Spring Boot 自動配置,您可以在其完全初始化之前透過公開實現 CacheManagerCustomizer 介面的 bean 來進一步調整其配置。以下示例設定了一個標誌,表示 null 值不應傳遞到底層對映
-
Java
-
Kotlin
import org.springframework.boot.cache.autoconfigure.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);
}
}
import org.springframework.boot.cache.autoconfigure.CacheManagerCustomizer
import org.springframework.cache.concurrent.ConcurrentMapCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
class MyCacheManagerConfiguration {
@Bean
fun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {
return CacheManagerCustomizer { cacheManager ->
cacheManager.isAllowNullValues = false
}
}
}
在前面的示例中,預期是自動配置的 ConcurrentMapCacheManager。如果不是這種情況(您提供了自己的配置或自動配置了不同的快取提供程式),則不會呼叫定製器。您可以擁有任意數量的定製器,並且還可以透過使用 @Order 或 Ordered 對它們進行排序。 |
通用
如果上下文定義了 至少 一個 Cache bean,則使用通用快取。將建立一個包裝所有該型別 bean 的 CacheManager。
JCache (JSR-107)
透過類路徑上存在 CachingProvider(即,類路徑上存在符合 JSR-107 的快取庫)來啟動 JCache,並且 spring-boot-starter-cache 啟動器提供了 JCacheCacheManager。提供了各種相容庫,Spring Boot 為 Ehcache 3、Hazelcast 和 Infinispan 提供依賴管理。也可以新增任何其他相容庫。
可能會出現多個提供程式的情況,在這種情況下,必須明確指定提供程式。即使 JSR-107 標準不強制規定配置檔案的標準化位置,Spring Boot 也會盡力適應使用實現細節設定快取,如以下示例所示
-
屬性
-
YAML
spring.cache.jcache.provider=com.example.MyCachingProvider
spring.cache.jcache.config=classpath:example.xml
# 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 全面支援 Hazelcast。如果存在單個 HazelcastInstance,除非指定了 spring.cache.jcache.config 屬性,否則它也會自動重用於 CacheManager。 |
有兩種方法可以自定義底層 CacheManager
-
可以透過設定
spring.cache.cache-names屬性在啟動時建立快取。如果定義了自定義的Configurationbean,則會使用它來自定義它們。 -
使用
CacheManager的引用呼叫CacheManagerCustomizerbean 進行完全自定義。
如果定義了標準的 CacheManager bean,它會自動包裝在抽象所期望的 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 沒有預設配置檔案位置,因此必須明確指定。否則,將使用預設的載入程式。
-
屬性
-
YAML
spring.cache.infinispan.config=infinispan.xml
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.* 屬性配置快取預設值。例如,以下配置建立了 cache1 和 cache2 快取,其條目 過期時間 為 10 分鐘
-
屬性
-
YAML
spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
spring:
cache:
cache-names: "cache1,cache2"
couchbase:
expiration: "10m"
如果您需要對配置進行更多控制,請考慮註冊一個 CouchbaseCacheManagerBuilderCustomizer bean。以下示例顯示了一個定製器,它為 cache1 和 cache2 配置了特定的條目過期時間
-
Java
-
Kotlin
import java.time.Duration;
import org.springframework.boot.cache.autoconfigure.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)));
}
}
import org.springframework.boot.cache.autoconfigure.CouchbaseCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
import java.time.Duration
@Configuration(proxyBeanMethods = false)
class MyCouchbaseCacheManagerConfiguration {
@Bean
fun myCouchbaseCacheManagerBuilderCustomizer(): CouchbaseCacheManagerBuilderCustomizer {
return CouchbaseCacheManagerBuilderCustomizer { 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.* 屬性配置快取預設值。例如,以下配置建立了 cache1 和 cache2 快取,其 存活時間 為 10 分鐘
-
屬性
-
YAML
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=10m
spring:
cache:
cache-names: "cache1,cache2"
redis:
time-to-live: "10m"
預設情況下,會新增一個鍵字首,這樣,如果兩個獨立的快取使用相同的鍵,Redis 就不會有重疊的鍵,並且不會返回無效值。如果您建立自己的 RedisCacheManager,我們強烈建議保持此設定啟用。 |
您可以透過新增自己的 RedisCacheConfiguration @Bean 來完全控制預設配置。如果您需要自定義預設的序列化策略,這會很有用。 |
如果您需要對配置進行更多控制,請考慮註冊一個 RedisCacheManagerBuilderCustomizer bean。以下示例顯示了一個定製器,它為 cache1 和 cache2 配置了特定的存活時間
-
Java
-
Kotlin
import java.time.Duration;
import org.springframework.boot.cache.autoconfigure.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)));
}
}
import org.springframework.boot.cache.autoconfigure.RedisCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import java.time.Duration
@Configuration(proxyBeanMethods = false)
class MyRedisCacheManagerConfiguration {
@Bean
fun myRedisCacheManagerBuilderCustomizer(): RedisCacheManagerBuilderCustomizer {
return RedisCacheManagerBuilderCustomizer { 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 啟動器提供)。可以透過設定 spring.cache.cache-names 屬性在啟動時建立快取,並且可以透過以下方式(按所示順序)進行自定義
-
由
spring.cache.caffeine.spec定義的快取規範 -
定義了一個
CaffeineSpecbean -
定義了一個
Caffeinebean
例如,以下配置建立了 cache1 和 cache2 快取,其最大大小為 500,存活時間 為 10 分鐘
-
屬性
-
YAML
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
spring:
cache:
cache-names: "cache1,cache2"
caffeine:
spec: "maximumSize=500,expireAfterAccess=600s"
如果定義了 CacheLoader bean,它會自動與 CaffeineCacheManager 關聯。由於 CacheLoader 將與快取管理器管理的所有快取關聯,因此它必須定義為 CacheLoader<Object, Object>。自動配置會忽略任何其他泛型型別。
Cache2k
Cache2k 是一個記憶體快取。如果存在 Cache2k spring 整合,則會自動配置 SpringCache2kCacheManager。
可以透過設定 spring.cache.cache-names 屬性在啟動時建立快取。快取預設值可以透過 Cache2kBuilderCustomizer bean 進行自定義。以下示例顯示了一個定製器,它將快取容量配置為 200 個條目,過期時間為 5 分鐘
-
Java
-
Kotlin
import java.util.concurrent.TimeUnit;
import org.springframework.boot.cache.autoconfigure.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);
}
}
import org.springframework.boot.cache.autoconfigure.Cache2kBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.TimeUnit
@Configuration(proxyBeanMethods = false)
class MyCache2kDefaultsConfiguration {
@Bean
fun myCache2kDefaultsCustomizer(): Cache2kBuilderCustomizer {
return Cache2kBuilderCustomizer { builder ->
builder.entryCapacity(200)
.expireAfterWrite(5, TimeUnit.MINUTES)
}
}
}
簡單
如果找不到其他任何提供程式,則會配置一個使用 ConcurrentHashMap 作為快取儲存的簡單實現。如果您的應用程式中沒有快取庫,則這是預設設定。預設情況下,快取會按需建立,但您可以透過設定 cache-names 屬性來限制可用快取列表。例如,如果您只想要 cache1 和 cache2 快取,請按如下方式設定 cache-names 屬性
-
屬性
-
YAML
spring.cache.cache-names=cache1,cache2
spring:
cache:
cache-names: "cache1,cache2"
如果您這樣做並且您的應用程式使用了未列出的快取,那麼它會在需要快取時在執行時失敗,而不是在啟動時失敗。這類似於“真實”快取提供程式在使用未宣告的快取時的行為方式。
無
當您的配置中存在 @EnableCaching 時,也期望有一個合適的快取配置。如果您有自定義的 org.springframework.cache.CacheManager,請考慮在單獨的 @Configuration 類中定義它,以便在必要時可以覆蓋它。None 使用無操作實現,這在測試中很有用,並且當 spring-boot-cache-test 模組存在時,切片測試預設透過 @AutoConfigureCache 使用它。
如果您需要在某個環境中而不是自動配置的快取管理器中使用無操作快取,請將快取型別設定為 none,如以下示例所示
-
屬性
-
YAML
spring.cache.type=none
spring:
cache:
type: "none"