Configuring the Cache Storage

缓存抽象提供了多种存储集成选项。要使用它们,您需要声明一个适当的 CacheManager(一个控制和管理 Cache 实例且可用于检索它们以进行存储的实体)。

The cache abstraction provides several storage integration options. To use them, you need to declare an appropriate CacheManager (an entity that controls and manages Cache instances and that can be used to retrieve these for storage).

JDK ConcurrentMap-based Cache

基于 JDK 的 Cache 实现位于 org.springframework.cache.concurrent 包中。它使你可以使用 ConcurrentHashMap 作为支持 Cache 存储。以下示例演示如何配置两个缓存:

The JDK-based Cache implementation resides under org.springframework.cache.concurrent package. It lets you use ConcurrentHashMap as a backing Cache store. The following example shows how to configure two caches:

  • Java

  • Kotlin

  • Xml

@Bean
ConcurrentMapCacheFactoryBean defaultCache() {
	ConcurrentMapCacheFactoryBean cache = new ConcurrentMapCacheFactoryBean();
	cache.setName("default");
	return cache;
}

@Bean
ConcurrentMapCacheFactoryBean booksCache() {
	ConcurrentMapCacheFactoryBean cache = new ConcurrentMapCacheFactoryBean();
	cache.setName("books");
	return cache;
}

@Bean
CacheManager cacheManager(ConcurrentMapCache defaultCache, ConcurrentMapCache booksCache) {

	SimpleCacheManager cacheManager = new SimpleCacheManager();
	cacheManager.setCaches(Set.of(defaultCache, booksCache));
	return cacheManager;
}
@Bean
fun defaultCache(): ConcurrentMapCacheFactoryBean {
	return ConcurrentMapCacheFactoryBean().apply {
		setName("default")
	}
}

@Bean
fun booksCache(): ConcurrentMapCacheFactoryBean {
	return ConcurrentMapCacheFactoryBean().apply {
		setName("books")
	}
}

@Bean
fun cacheManager(defaultCache: ConcurrentMapCache, booksCache: ConcurrentMapCache): CacheManager {
	return SimpleCacheManager().apply {
		setCaches(setOf(defaultCache, booksCache))
	}
}
<!-- simple cache manager -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
	<property name="caches">
		<set>
			<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="default"/>
			<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="books"/>
		</set>
	</property>
</bean>

前一代码段使用`SimpleCacheManager`创建一个`CacheManager`用于两个嵌套的`ConcurrentMapCache`,实例名为`default`和`books`。请注意,名称是针对每个缓存直接配置的。

The preceding snippet uses the SimpleCacheManager to create a CacheManager for the two nested ConcurrentMapCache instances named default and books. Note that the names are configured directly for each cache.

由于缓存是由应用程序创建的,因此它与应用程序的生命周期绑定,使其适合基本用例、测试或简单应用程序。缓存扩展性好并且非常快,但它不提供任何管理功能、持久性功能或驱逐协定。

As the cache is created by the application, it is bound to its lifecycle, making it suitable for basic use cases, tests, or simple applications. The cache scales well and is very fast, but it does not provide any management, persistence capabilities, or eviction contracts.

Ehcache-based Cache

Ehcache 3.x 完全符合 JSR-107,不需要针对它提供专属支持。有关详细信息,请参见 JSR-107 Cache

Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it. See JSR-107 Cache for details.

Caffeine Cache

Caffeine是Guava 缓存的 Java 8 重写版本,其实现位于`org.springframework.cache.caffeine`包中,并且提供对 Caffeine 的若干功能的访问权限。

Caffeine is a Java 8 rewrite of Guava’s cache, and its implementation is located in the org.springframework.cache.caffeine package and provides access to several features of Caffeine.

以下示例配置了一个按需创建缓存的`CacheManager`:

The following example configures a CacheManager that creates the cache on demand:

  • Java

  • Kotlin

  • Xml

@Bean
CacheManager cacheManager() {
	return new CaffeineCacheManager();
}
@Bean
fun cacheManager(): CacheManager {
	return CaffeineCacheManager()
}
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/>

你还可以显式提供要使用的缓存。在这种情况下,只有那些缓存是由管理器提供的。以下示例展示了如何这样做:

You can also provide the caches to use explicitly. In that case, only those are made available by the manager. The following example shows how to do so:

  • Java

  • Kotlin

  • Xml

@Bean
CacheManager cacheManager() {
	CaffeineCacheManager cacheManager = new CaffeineCacheManager();
	cacheManager.setCacheNames(List.of("default", "books"));
	return cacheManager;
}
@Bean
fun cacheManager(): CacheManager {
	return CaffeineCacheManager().apply {
		cacheNames = listOf("default", "books")
	}
}
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager">
	<property name="cacheNames">
		<set>
			<value>default</value>
			<value>books</value>
		</set>
	</property>
</bean>

Caffeine CacheManager 还支持自定义 CaffeineCacheLoader。有关它们的详细信息,请参见 Caffeine documentation

The Caffeine CacheManager also supports custom Caffeine and CacheLoader. See the Caffeine documentation for more information about those.

GemFire-based Cache

GemFire 是面向内存、支持磁盘、弹性可缩放、持续可用,主动(带有基于内置模式的订阅通知)的全局复制数据库,并提供功能齐全的边缘缓存。有关如何将 GemFire 用作 `CacheManager`的详细信息(以及更多其他信息),请参见https://docs.spring.io/spring-gemfire/docs/current/reference/html/[Spring Data GemFire 参考文档]。

GemFire is a memory-oriented, disk-backed, elastically scalable, continuously available, active (with built-in pattern-based subscription notifications), globally replicated database and provides fully-featured edge caching. For further information on how to use GemFire as a CacheManager (and more), see the Spring Data GemFire reference documentation.

JSR-107 Cache

Spring的缓存抽象还可以使用符合 JSR-107 的缓存。JCache 实现位于`org.springframework.cache.jcache`包中。

Spring’s caching abstraction can also use JSR-107-compliant caches. The JCache implementation is located in the org.springframework.cache.jcache package.

同样,要使用它,你需要声明合适的`CacheManager`。以下示例展示了如何这样做:

Again, to use it, you need to declare the appropriate CacheManager. The following example shows how to do so:

  • Java

  • Kotlin

  • Xml

@Bean
javax.cache.CacheManager jCacheManager() {
	CachingProvider cachingProvider = Caching.getCachingProvider();
	return cachingProvider.getCacheManager();
}

@Bean
org.springframework.cache.CacheManager cacheManager(javax.cache.CacheManager jCacheManager) {
	return new JCacheCacheManager(jCacheManager);
}
@Bean
fun jCacheManager(): javax.cache.CacheManager {
	val cachingProvider = Caching.getCachingProvider()
	return cachingProvider.getCacheManager()
}

@Bean
fun cacheManager(jCacheManager: javax.cache.CacheManager): org.springframework.cache.CacheManager {
	return JCacheCacheManager(jCacheManager)
}
<bean id="cacheManager"
	  class="org.springframework.cache.jcache.JCacheCacheManager"
	  p:cache-manager-ref="jCacheManager"/>

<!-- JSR-107 cache manager setup  -->
<bean id="jCacheManager" .../>

Dealing with Caches without a Backing Store

有时候,在切换环境或进行测试时,你可能会有缓存声明,而没有配置实际的支持缓存。由于这是一个无效配置,因此会在运行时抛出异常,因为缓存基础设施找不到合适的存储。在这种情况下,你可以接入一个简单的虚拟缓存,而不是删除缓存声明(这可能很繁琐),该缓存不执行任何缓存——即每次都强制调用被缓存的方法。以下示例展示了如何这样做:

Sometimes, when switching environments or doing testing, you might have cache declarations without having an actual backing cache configured. As this is an invalid configuration, an exception is thrown at runtime, since the caching infrastructure is unable to find a suitable store. In situations like this, rather than removing the cache declarations (which can prove tedious), you can wire in a simple dummy cache that performs no caching — that is, it forces the cached methods to be invoked every time. The following example shows how to do so:

  • Java

  • Kotlin

  • Xml

@Bean
CacheManager cacheManager(CacheManager jdkCache, CacheManager gemfireCache) {
	CompositeCacheManager cacheManager = new CompositeCacheManager();
	cacheManager.setCacheManagers(List.of(jdkCache, gemfireCache));
	cacheManager.setFallbackToNoOpCache(true);
	return cacheManager;
}
@Bean
fun cacheManager(jdkCache: CacheManager, gemfireCache: CacheManager): CacheManager {
	return CompositeCacheManager().apply {
		setCacheManagers(listOf(jdkCache, gemfireCache))
		setFallbackToNoOpCache(true)
	}
}
<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
	<property name="cacheManagers">
		<list>
			<ref bean="jdkCache"/>
			<ref bean="gemfireCache"/>
		</list>
	</property>
	<property name="fallbackToNoOpCache" value="true"/>
</bean>

前面的`CompositeCacheManager`链接了多个`CacheManager`实例,并且通过`fallbackToNoOpCache`标志,为所有未经配置的缓存管理器处理的定义添加了一个无操作缓存。即,每个在`jdkCache`或`gemfireCache`(在示例中前面配置)中找不到的缓存定义都由无操作缓存处理,该缓存不存储任何信息,导致每次都会调用目标方法。

The CompositeCacheManager in the preceding chains multiple CacheManager instances and, through the fallbackToNoOpCache flag, adds a no-op cache for all the definitions not handled by the configured cache managers. That is, every cache definition not found in either jdkCache or gemfireCache (configured earlier in the example) is handled by the no-op cache, which does not store any information, causing the target method to be invoked every time.