快取
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
屬性定義的預設快取。
支援的快取提供者
快取抽象概念不提供實際的儲存,而是依賴於 org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
介面實現的抽象概念。
如果您尚未定義類型為 CacheManager
的 bean 或名為 cacheResolver
的 CacheResolver
(請參閱 CachingConfigurer
),Spring Boot 會嘗試偵測下列提供者 (依指示的順序)
-
JCache (JSR-107) (EhCache 3、Hazelcast、Infinispan 等)
如果 CacheManager 由 Spring Boot 自動組態,則可以透過設定 spring.cache.type 屬性來強制使用特定的快取提供者。 如果您需要在某些環境 (例如測試) 中使用 no-op 快取,請使用此屬性。 |
使用 `spring-boot-starter-cache` 啟動器快速新增基本快取依賴。 此啟動器引入了 `spring-context-support`。 如果您手動新增依賴,則必須包含 `spring-context-support` 才能使用 JCache 或 Caffeine 支援。 |
如果 CacheManager
由 Spring Boot 自動組態,您可以在完全初始化之前,透過公開實作 `CacheManagerCustomizer` 介面的 bean 來進一步調整其組態。 下列範例設定一個旗標,表示不應將 null
值傳遞到基礎映射
-
Java
-
Kotlin
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);
}
}
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)
class MyCacheManagerConfiguration {
@Bean
fun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {
return CacheManagerCustomizer { cacheManager ->
cacheManager.isAllowNullValues = false
}
}
}
在前面的範例中,預期會自動組態 `ConcurrentMapCacheManager`。 如果情況並非如此 (您提供了自己的組態或自動組態了不同的快取提供者),則完全不會調用自訂器。 您可以擁有任意數量的自訂器,也可以使用 `@Order` 或 `Ordered` 對它們進行排序。 |
JCache (JSR-107)
JCache 是透過類別路徑上存在 `javax.cache.spi.CachingProvider` 來引導的 (也就是說,類別路徑上存在符合 JSR-107 標準的快取庫),而 `JCacheCacheManager` 由 `spring-boot-starter-cache` 啟動器提供。 有各種符合標準的庫可用,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` 可用,它也會自動重複用於 `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 沒有預設組態檔位置,因此必須明確指定。 否則,將使用預設引導。
-
屬性
-
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.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)));
}
}
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
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.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)));
}
}
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
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` 定義的快取規格
-
已定義 `com.github.benmanes.caffeine.cache.CaffeineSpec` bean
-
已定義 `com.github.benmanes.caffeine.cache.Caffeine` bean
例如,下列組態會建立 `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"
如果定義了 `com.github.benmanes.caffeine.cache.CacheLoader` bean,則會自動將其與 `CaffeineCacheManager` 關聯。 由於 `CacheLoader` 將與快取管理器管理的所有快取關聯,因此必須將其定義為 `CacheLoader<Object, Object>`。 自動組態會忽略任何其他泛型類型。
Cache2k
Cache2k 是一種記憶體內快取。 如果 Cache2k Spring Integration 存在,則會自動組態 `SpringCache2kCacheManager`。
可以透過設定 `spring.cache.cache-names` 屬性在啟動時建立快取。 可以使用 `Cache2kBuilderCustomizer` bean 自訂快取預設值。 下列範例顯示了一個自訂器,該自訂器將快取的容量組態為 200 個項目,到期時間為 5 分鐘
-
Java
-
Kotlin
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);
}
}
import org.springframework.boot.autoconfigure.cache.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"
如果您這樣做,並且您的應用程式使用了未列出的快取,則在需要快取時,執行階段會失敗,但啟動時不會失敗。 這與如果您使用未宣告的快取時,「真實」快取提供者的行為方式類似。