写点什么

整天都在讨论使用 SpringBoot,可你居然连缓存都不清楚

用户头像
小Q
关注
发布于: 2020 年 12 月 05 日

缓存技术是一个让所有开发人员又爱又恨的技术,我们爱缓存是因为缓存能给我们带来数量级的响应和流量,但是最迷人的反而最危险,如果缓存用不好也是灾难级别的,特别是一些涉及到公司主要现金流的业务,如果因为我们使用缓存不当,而带给公司一定的损失,不亚于删库跑路的那个大兄弟,那今天我们就来看一下 springboot 的缓存都有那些东西,学习嘛,一点点的来,慢慢积累自己的经验,才能厚积薄发


个人公众号:Java 架构师联盟,每日更新技术好文


一、JSR107 缓存规范


为了缓存开发规范的统一,以及提升系统的扩展性,J2EE 发布了 JSR107 缓存规范。主要是 Java Caching 定义了 5 个接口,分别是 CachingProvider、CacheManager、Cache、Entry、Expiry。


下面我们分开详细的展开看一下


  • CachingProvider:

  • 可以创建、配置、获取、管理和控制多个 CacheManager,一个 Application 在运行期间可以访问多个 CachingProvider。

  • CacheManager:

  • 可以创建、配置、获取、管理和控制多个唯一命名的 Cache,这些 Cache 存在于 CacheManager 的上下文中。一个 CacheManager 仅被一个 CachingProvider 所拥有。

  • Cache:

  • 是一个类似于 Map 的数据结构并临时存储以 Key 为索引的值。一个 Cache 仅被一个 CacheManager 所拥有。

  • Entry:

  • 是存储在 Cache 中的 Key-Value 对。

  • Expiry:

  • 每一个缓存在 Cache 中的条目有一个定义的有效期,一旦超过这个时间,该条目就为过期状态,一旦过期,条目将不可访问、更新和删除。其中缓存的有效期可以通过 ExpiryPolicy 设置。

  • 如果说这样讲解让你有点蒙圈的话,那没关系,我们看下面这张图



简单总结一下就是:一个应用里面可以有多个缓存提供者(CachingProvider),一个缓存提供者可以获取到多个缓存管理器(CacheManager),一个缓存管理器管理着不同的缓存(Cache),缓存中是一个个的缓存键值对(Entry),每个 entry 都有一个有效期(Expiry)。缓存管理器和缓存之间的关系有点类似于数据库中连接池和连接的关系。


二、SpringBoot 缓存抽象


在我自己看来,没有源码所有的理论讲解,都是空谈,或者说就是扯淡,所以我们来看一下,缓存的源码级操作


Spring 从 3.1 版本开始定义了 org.springframework.cache.CacheManager org.springframework.cache.Cache 接口来统一不同的缓存技术,并支持使用 JSR-107 注解简化开发。在 IDEA 中,使用 Spring Initializr 快速创建 Spring Boot 项目时,勾选中 Cache 后,在配置文件中配置 debug=true,可以查看 Spring Boot 的自动配置项。其中关于缓存的配置类如下:


org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
复制代码


org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
复制代码

启动项目后,可以在控制台看到匹配到的只有 SimpleCacheConfiguration 这个自动配置类,而在 SimpleCacheConfiguration 类中,使用 @Bean 注解给容器中注册了一个 CacheManager,由此可看 Spring Boot 默认的 CacheManager 是 ConcurrentMapCacheManager。


 SimpleCacheConfiguration matched:
复制代码


      - Cache org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration automatic cache type (CacheCondition)
复制代码


      - @ConditionalOnMissingBean (types: org.springframework.cache.CacheManager; SearchStrategy: all) did not find any beans (OnBeanCondition)
复制代码

同样的,我们通过一张图形象的展示一下看看



几个重要概念和缓存注解:



进入 @Caching 的源码可以看到,在组合注解内可以使用 cacheable、put、evict


public @interface Caching {
复制代码


    Cacheable[] cacheable() default {};
复制代码


复制代码


    CachePut[] put() default {};
复制代码


复制代码


    CacheEvict[] evict() default {};
复制代码


}
复制代码

@Caching 的使用


 @Caching(
复制代码


            cacheable = {
复制代码


                    @Cacheable(key = "#name")
复制代码


            },
复制代码


            put = {
复制代码


                    @CachePut(key = "#result.id"),
复制代码


                    @CachePut(key = "#result.cNo")
复制代码


            }
复制代码


    )
复制代码

@Cacheable、@CachePut、@CacheEvict 中的主要参数


key


#缓存的key,可以为空,也可以使用SpEL表达式编写
复制代码


例:@Cacheable(value=“stu”,key=“userName”)
复制代码

condition


#缓存的条件,可以为空,也可以使用SpEL表达式编写,只有为true才缓存/清除缓存,
复制代码


#不管方法执行前后都可以判断
复制代码


例:@Cacheable(value=“stu”,condition=“userName.length()>2”)
复制代码

unless


#用于否定缓存,只在方法执行之后判断,也可以使用SpEL表达式编写
复制代码


#true不缓存,false才缓存
复制代码


例:@Cacheable(value=“stu”,unless=“userName == null”)
复制代码
  • @Cacheable

  • 标注的方法执行之前,先查看缓存中有没有这个数据,默认按照参数的值作为 key 去缓存中查找。如果没有就运行这个方法并将方法的执行结果放入缓存中,之后再调用该方法时,直接使用缓存中的数据即可。

  • @CachePut

  • 标注的方法必须要执行,它的运行时机是,先调用目标方法,然后将目标方法的结果放入缓存中,但是更新缓存中的数据时,要注意 key 值,否则缓存中的数据无法更新。

  • @CacheEvict

  • 这个注解中 allEntries = true 代表要清除某个缓存中的所有数据。beforeInvocation = false 代表缓存的清除在方法执行之后执行,如果出现异常等情况,则不会清除缓存中的数据。这是 @CacheEvict

  • 注解默认的。beforeInvocation = true 代表缓存的清除在方法执行之前执行,出现异常等情况,也会清除缓存中的数据。

  • key 的生成策略

  • key 的生成默认使用 SimpleKeyGenerator 生成的,而 SimpleKeyGenerator 的生成策略有:如果没有参数:key=new SimpleKey();如果有一个参数:key=参数的值如果有多个参数:key=new SimpleKey(params);


发布于: 2020 年 12 月 05 日阅读数: 32
用户头像

小Q

关注

还未添加个人签名 2020.06.30 加入

小Q 公众号:Java架构师联盟 作者多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果能为您提供帮助,请给予支持(关注、点赞、分享)!

评论

发布
暂无评论
整天都在讨论使用SpringBoot,可你居然连缓存都不清楚