Spring Boot 如何选择 Cache 实现的

写作此篇是作为对 Spring 使用 Cache 解析及使用不同类型的 Cache 一文的补充,该文中提到了自定 CacheManager 及配置 spring.cache.type 来选择自己的 Cache 实例,但对 Spring 是如何确定具体 Cache 实现未作展开。本文将介绍选择 Cache 实现的几种方式

  1. 默认选择 Cache
  2. 声明 Spring Bean Cache
  3. 声明 Spring Bean CacheManager
  4. 通过 spring.cache.type 属性选择
  5. 引入相应的 Cache 实现依赖

首先来看 SpringBoot 所有支持的 Cache 实现,在 CacheConfigurations 类中,我们看到

或者是在 CacheType 中的枚举值定义

我们目前所能选择的 Cache 实现只能出自于上面几种,当然通过定义 Cache(GenericCacheCofiguration)CacheManager(SimpleCacheConfiguration) 的方式就能无限可能了。

注意, CacheType 枚举值的定义也决定了 Spring 引入相应的 XXXCacheConfiguration 类的顺序,这对选择使用哪种 Cache 是有影响的。

默认选择 Cache

当我们在一个干净的 Spring 环境中,以上的 #2 - #5 的条件都未满足的情况下,SpringBoot 将选择 SimpleCacheConfiguration, 而不是 GenericCacheConfiguration. 原因是这两个 SpringBean 依赖的条件不同

SimpleCacheConfiguration

GenericCacheConfiguration

因为 Cache Bean 也不存在,所以选择的是 SimpleCacheConfiguration

再比较一下 NonOpCacheConfiguration

它和 SimpleCacheConfiguration 有相同的 @ConditionalXxx 条件,那为什么不会默认为 NoOpCacheConfiguration 呢?

原因是在 CacheAutoConfiguration.CacheConfigurationIMportSelector.selectImports() 方法中先引入的是 SimpleCacheConfiguration,NoOpCacheConfiguration 是最后被引入的。 它在初始化 CacheManager 实例(ConcurrentMapCacheManager) 后,使得 NoOpCacheConfiguration@OnditionalOnMissingBean(CacheManager.class) 不能满足,所以选择的是 SimpleCacheConfiguration

而其他的使用了第三方库的 Cache 必须依赖于是否引入了相应的库。

声明了 Cache Bean 后选择 GenericCacheConfiguration

仍然要记记住 Spring 引入以下三种无第三方库依赖的 XxxCacheConfiguration 的顺序是

  1. GenericCacheConfiguration
  2. SimpleCacheConfiguration
  3. NoOpCacheConfiguration

它们都不想看到 CacheManager 实例,但 GenericCacheConfiguration 在存在 Cache 实例时被选择,所以只要声明一个自己的 Cache

验证很简单,在 Java config 中声明一个 Cache

这样的话,使用 @Cacheable 等注解将会使用 GenericCacheConfiguration 实现

声明了 CacheManager Bean 就直接用该 CacheManager

所有 XxxCacheConfiguration 都排斥 CacheManager Bean, 所以只要声明了自己的 CacheManager 的话就很明确了,没有其他任何的 XxxCacheConfigruation 的事情了。

比如我们使用 Google Guava 的 Cache

通过 spring.cache.type 选择 Cache

在既没有 CacheCacheManager Bean 实例定义的情况下,如果设置属性 spring.cache.type=None, 将会选择 NoOpCacheConfiguration 中定义的 NoOpCacheManager, 因为 spring.cache.type=None 将会产生下面的效果

  1. GenericCacheConfiguration: @Conditional(CacheCondition.class) match = false
  2. SimpleCacheConfiguration: @Conditional(CacheCondition.class) match = false
  3. NoOpCacheConfiguration: @Conditional(CacheCondition.class) match = true

唯有 NoOpCacheConfiguration 能满足初始化的条件

所以通过配置 spring.cache.type 可以强制选择所需的 XxxCacheConfiguration,以及其中的 CacheManager, 而不管在自己的应用中是否声明了自己 Cache 或 CacheManager,因为 spring.cache.type 直接否决掉不符合条件的 @Conditional(CacheCondition.class)。

启用第三方 Cache 实现

欲知如何启用第三方的 Cache 实现,那就直接看相应的 XxxCacheConfiguration 需满足的条件。其实对前面讲到的 GenericCacheConfiguration, SimpleCacheConfigruation, 和  NoOpCacheConfigruation 都是相同的道理。

比如要用 EhCache 的话,打开 EhcacheCacheConfiguration 类的声明

必须满足的条件有

  1. 存在类 net.sf.ehcache.Cacheorg.springframework.cache.ehcache.EhCacheCacheManager
  2. 不要声明 CacheManager Bean
  3. 不要配置 spring.cache.type,有 spring.cache.type 的话,值只能为 Ehcache(不区分大小写)
  4. 要配置 Ehcache 的配置文件 classpath:/ehcache.xml

注:spring.cache.type 除了设置为 None 禁用 Cache 用,其实没什么用

因此我们要做的就是(假定为 Maven 项目)

引入依赖,在 pom.xml 中要具备

添加 Ehcache 配置文件 src/main/resources/ehcache.xml

这是一个最简陋但能工作的配置文件

现在使用 @Cacheable 等注解将使用 Ehcache 缓存。

其他的 Cache 实现也类似,再比如 CaffeienCacheConfiguration

要有 com.github.benmanes.caffeine.cache.Caffeine 类等条件。

如果不清楚 XxxCacheConfiguration 是否能被初始化, 可在 application.properties 中配置 debug=true, 输出 CONDITIONS EVALUATION REPORT 的内容

EhCacheCacheConfiguration matched:
    - @ConditionalOnClass found required classes 'net.sf.ehcache.Cache', 'org.springframework.cache.ehcache.EhCacheCacheManager' (OnClassCondition)
    - Cache org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration EHCACHE cache type (CacheCondition)
    - ResourceCondition (EhCache) found resource 'classpath:/ehcache.xml' (EhCacheCacheConfiguration.ConfigAvailableCondition)
    - @ConditionalOnMissingBean (types: org.springframework.cache.CacheManager; SearchStrategy: all) did not find any beans (OnBeanCondition)

CaffeineCacheConfiguration:
Did not match:
    - @ConditionalOnClass did not find required class 'com.github.benmanes.caffeine.cache.Caffeine' (OnClassCondition)

本文链接 https://yanbin.blog/how-springboot-select-cache-implementation/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments