Springcloud学习笔记68--springboot 整合Caffeine 本地缓存

1 本地缓存介绍

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。

之前介绍过 Redis 这种 NoSql 作为缓存组件,它能够很好的作为分布式缓存组件提供多个服务间的缓存,但是 Redis 这种还是需要网络开销,增加时耗。本地缓存是直接从本地内存中读取,没有网络开销,例如秒杀系统或者数据量小的缓存等,比远程缓存更合适。

2 缓存组件 Caffeine 介绍

按 Caffeine Github 文档描述,Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。

3 具体使用案例

3.1 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.9.3</version>
</dependency>

 3.2 缓存使用步骤

3.2.0 基础知识

在Cache接口中,定义了get、put、evict、clear等方法,分别对应缓存的存入、取出、删除、清空操作。不过我们这里不直接使用Cache接口,AbstractValueAdaptingCache是一个抽象类,它已经实现了Cache接口,是spring在Cache接口的基础上帮助我们进行了一层封装,所以我们直接继承这个类就可以。

继承AbstractValueAdaptingCache抽象类后,除了创建Cache的构造方法外,还需要实现下面的几个方法:

// 在缓存中实际执行查找的操作,父类的get()方法会调用这个方法
protected abstract Object lookup(Object key);

// 通过key获取缓存值,如果没有找到,会调用valueLoader的call()方法
public <T> T get(Object key, Callable<T> valueLoader);

// 将数据放入缓存中
public void put(Object key, Object value);

// 删除缓存
public void evict(Object key);

// 清空缓存中所有数据
public void clear();

// 获取缓存名称,一般在CacheManager创建时指定
String getName();

// 获取实际使用的缓存
Object getNativeCache();

而CaffeineCache就实现了这些方法;

3.2.1 开启基于注解的缓存

第一步:开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上

3.2.2 缓存配置类CacheConfig

Caffeine常用配置说明:

    initialCapacity=[integer]: 初始的缓存空间大小
    maximumSize=[long]: 缓存的最大条数
    maximumWeight=[long]: 缓存的最大权重
    expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
    expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
    refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
    weakKeys: 打开key的弱引用
    weakValues:打开value的弱引用
    softValues:打开value的软引用
    recordStats:开发统计功能
    
    注意:
    expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准。
    maximumSize和maximumWeight不可以同时使用
    weakValues和softValues不可以同时使用

需要说明的是,使用配置文件的方式来进行缓存项配置,一般情况能满足使用需求,但是灵活性不是很高,如果我们有很多缓存项的情况下写起来会导致配置文件很长。所以一般情况下你也可以选择使用bean的方式来初始化Cache实例。

SimpleCacheManager
    这种缓存管理器允许你在应用程序启动时通过配置多个CaffeineCache来创建多个缓存。
    这种方式可以让你为每个方法单独配置缓存过期时间。
CaffeineCacheManager
    这种缓存管理器使用了一个全局的Caffeine配置来创建所有的缓存。
    这种方式不能为每个方法单独配置缓存过期时间,但是可以在程序启动时配置全局的缓存配置,这样就可以轻松地设置所有方法的缓存过期时间。
总结:
    如果你希望为每个方法单独配置缓存过期时间,那么建议使用第一种方式。

@Configuration
@EnableCaching
public class CacheConfig {
    /**
     * Caffeine配置说明:
     * initialCapacity=[integer]: 初始的缓存空间大小
     * maximumSize=[long]: 缓存的最大条数
     * maximumWeight=[long]: 缓存的最大权重
     * expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
     * expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
     * refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
     * weakKeys: 打开key的弱引用
     * weakValues:打开value的弱引用
     * softValues:打开value的软引用
     * recordStats:开发统计功能
     * 注意:
     * expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。
     * maximumSize和maximumWeight不可以同时使用
     * weakValues和softValues不可以同时使用
     */
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List list = new ArrayList<>();
        //循环添加枚举类中自定义的缓存,可以自定义
        for (CacheEnum cacheEnum : CacheEnum.values()) {
            list.add(new CaffeineCache(cacheEnum.getName(),
                    Caffeine.newBuilder()
                            .initialCapacity(50)
                            .maximumSize(1000)
                            .expireAfterAccess(cacheEnum.getExpires(), TimeUnit.SECONDS)
                            .build()));
        }
        cacheManager.setCaches(list);
        return cacheManager;
    }
}

3.2.3 标注缓存注解

具体调用缓存。

 注:这里使用 @Cacheable 注解就可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法。

cache方面的注解主要有以下5个:

  • @Cacheable 触发缓存入口(这里一般放在创建和获取的方法上,@Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存)
  • @CacheEvict 触发缓存的eviction(用于删除的方法上)
  • @CachePut 更新缓存且不影响方法执行(用于修改的方法上,该注解下的方法始终会被执行)
  • @Caching 将多个缓存组合在一个方法上(该注解可以允许一个方法同时设置多个注解)
  • @CacheConfig 在类级别设置一些缓存相关的共同配置(与其它缓存配合使用)

说一下@Cacheable 和 @CachePut的区别:

@Cacheable:它的注解的方法是否被执行取决于Cacheable中的条件,方法很多时候都可能不被执行。

@CachePut:这个注解不会影响方法的执行,也就是说无论它配置的条件是什么,方法都会被执行,更多的时候是被用到修改上。

下面介绍一下 @Cacheable 这个注解常用的几个属性:

  • cacheNames/value :用来指定缓存组件的名字
  • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
  • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用
  • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。
  • condition :可以用来指定符合条件的情况下才缓存
  • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
  • sync :是否使用异步模式。

① cacheNames

用来指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式,支持指定多个缓存。

② key

缓存数据时使用的 key。默认使用的是方法参数的值。可以使用 spEL 表达式去编写。

③ keyGenerator

key 的生成器,可以自己指定 key 的生成器,通过这个生成器来生成 key。

这样放入缓存中的 key 的生成规则就按照你自定义的 keyGenerator 来生成。不过需要注意的是:

@Cacheable 的属性,key 和 keyGenerator 使用的时候,一般二选一。

④ condition

符合条件的情况下才缓存。方法返回的数据要不要缓存,可以做一个动态判断。

⑤ unless

否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。

⑥ sync

是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中。

参考文献:

https://blog.csdn.net/m0_71777195/article/details/126225712

https://blog.csdn.net/zl1zl2zl3/article/details/110987968 (推荐)

https://blog.csdn.net/zhipengfang/article/details/121868030 (推荐)

https://zhuanlan.zhihu.com/p/109226599

https://m.elecfans.com/article/2329925.html

https://blog.csdn.net/Trunks2009/article/details/123982910

https://blog.csdn.net/u011943534/article/details/129164025

https://www.cnblogs.com/zhangzhixi/p/17029258.html

posted @ 2024-05-31 10:45  雨后观山色  阅读(984)  评论(0编辑  收藏  举报