配置缓存存储
缓存抽象提供了多种存储集成选项。要使用这些选项,您需要声明一个适当的CacheManager(一个控制和管理Cache实例的实体,可以用来检索和存储这些实例)。
基于JDK ConcurrentMap的缓存
基于JDK的Cache实现位于org.springframework.cache.concurrent包中。它允许你使用ConcurrentHashMap作为背层的Cache存储。以下示例展示了如何配置两个缓存:
- 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为两个嵌套的ConcurrentMapCache实例(分别命名为default和books)创建了一个CacheManager。请注意,每个缓存的名称是直接进行配置的。
由于缓存是由应用程序创建的,因此它与其生命周期紧密绑定,这使其适用于基本用例、测试或简单应用程序。该缓存具有良好的扩展性且速度非常快,但它不提供任何管理、持久化功能或淘汰策略。
基于Ehcache的缓存
Ehcache 3.x完全符合JSR-107标准,因此不需要专门的支持。详情请参见JSR-107缓存。
咖啡因缓存
Caffeine是Guava缓存机制在Java 8平台上的重写版本,其实现位于org.springframework.cache.caffeine包中,并提供了对Caffeine多种功能的访问支持。
以下示例配置了一个CacheManager,该CacheManager会根据需求创建缓存:
- Java
- Kotlin
- Xml
@Bean
CacheManager cacheManager() {
return new CaffeineCacheManager();
}
@Bean
fun cacheManager(): CacheManager {
return CaffeineCacheManager()
}
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/>
您也可以显式提供要使用的缓存。在这种情况下,只有这些缓存才会被管理器提供。以下示例展示了如何操作:
- Java
- Kotlin
- Xml
@Bean
CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCacheNames(List.of("default", "books"));
return cacheManager;
}
@Bean
fun cacheManager(): CacheManager {
return CaffeineCacheManager("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还支持自定义的Caffeine和CacheLoader。有关这些的更多信息,请参阅Caffeine文档。
基于GemFire的缓存
GemFire是一个以内存为中心、基于磁盘存储、具有弹性扩展能力、持续可用性、支持主动订阅通知(内置基于模式的订阅通知功能)的全球分布式数据库,并提供功能完备的边缘缓存。有关如何将GemFire作为CacheManager使用的更多信息,请参阅Spring Data GemFire参考文档。
JSR-107 缓存
Spring的缓存抽象也可以使用符合JSR-107标准的缓存。JCache实现位于org.springframework.cache.jcache包中。
再次强调,要使用它,你需要声明合适的CacheManager。以下示例展示了如何进行操作:
- 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" .../>
处理没有后备存储的缓存
有时,在切换环境或进行测试时,你可能会遇到有缓存声明但实际上并未配置相应的缓存的情况。由于这种配置是无效的,因此在运行时会抛出异常,因为缓存基础设施无法找到合适的存储位置。在这种情况下,与其删除缓存声明(这可能相当繁琐),不如使用一个简单的虚拟缓存来替代——也就是说,这个虚拟缓存不会执行任何缓存操作,而是强制每次都调用被缓存的方法。以下示例展示了如何实现这一点:
- 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 标志,为所有未被配置的缓存管理器处理的定义添加一个无操作(no-op)缓存。也就是说,任何在 jdkCache 或 gemfireCache(在示例中提前配置的缓存)中找不到的缓存定义,都会由这个无操作缓存来处理。该缓存不存储任何信息,因此每次都会调用目标方法。