本地缓存~

前言

Caffeine是使用Java8对Guava缓存的重写版本,在Spring Boot 2.0中取而代之,基于LRU算法实现,支持多种缓存过期策略。

以下摘抄于https://github.com/ben-manes/caffeine/wiki/Benchmarks-zh-CN

基准测试通过使用Java microbenchmark harness 来提供准确的分析结果。这些缓存将被如下配置,

  • Caffeine 和 ConcurrentLinkedHashMap根据CPU的数量调整其内部大小。
  • Guava 并发度被配置为 64 (默认情况下为 4 来减少内存开销)。请注意Guava将会#2063 解决性能问题,但已经被积压多年(提升25倍以上!)。
  • Ehcache v2 内部被硬编码为100段, 而 v3 版本没有进行分段
  • Infinispan “old” 是一个类似Guava的缓存,并且并发度被配置为64
  • Infinispan "new"是使用无锁deque(默认版本为 v7.2+)重写的

本地缓存对比

特性GuavaCaffeine
自动加载实体到缓存中✔️✔️
自动刷新✔️✔️
过期或被删除的机制✔️✔️
自动回收✔️✔️
统计累计访问缓存✔️✔️
异步✔️
写入外界资源✔️
算法S-LRU 分段的最近最少未使用算法W-TinyLFU 高命中率、低内存占用
持久化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用指南

pom引入

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

配置

  • maximumSize:

  • refreshAfterWrite

  • expireAfterWrite

  • expireAfterAccess

  • maximumWeight

preview

方法

  • Get

    如果Guava 的load()返回时null,那么get()会抛出异常ExecutionException,而Caffeine就不会,会返回null

  • getAll

    获取多个key的value,返回一个map

  • load

    刷新

  • getUnchecked(): guava才有,Caffeine没有,所以Caffeine需要做好控判断

  • Caffeine.newBuilder().build()创建LoadingCache

  • invalidate

  • cleanUp

缓存填充方法

  • 手动填充

    # 0. 构建LoadingCache
    Cache<String, DataObject> cache = Caffeine.newBuilder()
      .expireAfterWrite(1, TimeUnit.MINUTES)
      .maximumSize(280)
      .build();
      
    String key = "test";
    # 1. 缓存中不存指定的值,则方法将返回 null
    DataObject dataObject = cache.getIfPresent(key); 
    
    cache.put(key, "20220510 Demo演示");
    # 2. return "20220510 Demo演示"
    dataObject = cache.getIfPresent(key);
    
    # 3. 如果key的值不存在,则返回“空时mock一个值”
    dataObject = cache
      .get(key, k -> "空时mock一个值"); 
    
    # 4. 手动失效
    cache.invalidate(key);
    # 返回null
    dataObject = cache.getIfPresent(key);
    
  • 同步加载

    LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
      .maximumSize(100)
      .expireAfterWrite(1, TimeUnit.MINUTES)
      .build(k -> "Data for " + k);
    
  • 异步加载

    AsyncLoadingCache<String, DataObject> cache = Caffeine.newBuilder()
      .maximumSize(100)
      .expireAfterWrite(1, TimeUnit.MINUTES)
      .buildAsync(k -> "Data for " + k);
    
    String key = "test-async";
     
    cache.get(key).thenAccept(dataObject -> {
        assertNotNull(dataObject);
        assertEquals("Data for " + key, dataObject.getData());
    });
     
    cache.getAll(Arrays.asList("test-async", "test-async2", "test-async3"))
      .thenAccept(dataObjectMap -> assertEquals(3, 3));
    

注解的实现方式

Springboot 配置

spring:
# 配置缓存,初始缓存容量为10,最大容量为200,过期时间(这里配置写入后过期时间为3秒)
  cache:
    type: caffeine
    caffeine:
      spec: initialCapacity=10,maximumSize=200,expireAfterWrite=3s

@Cacheable

 // key 是指传入时的参数
 @Cacheable(value="users", key="#id")
 public Integer find(Integer id) {
     return id;
 }
// 表示第一个参数
@Cacheable(value="users", key="#p0")
 public Long find(Long id) {
     return id;
 }
// 表示User中的id值
 @Cacheable(value="users", key="#user.id")
 public User find(User user) {
      return user;
 }
 // 表示第一个参数里的id属性值
 @Cacheable(value="users", key="#p0.id")
 public User find(User user) {
     return user;
 }

// 表示第一个参数里的id属性值
 @Cacheable(value="users", key="#root.getXXX(#user.id)")
 public User find(User user) {
     return user;
 }

public String getXXX(String id){
  // 获取上文问的traceid 方法
  // ...
  return 上下文的traceId;
}
 // 根据条件判断是否缓存
 @Cacheable(value="users", key="#user.id", condition="#user.id%2==0"/*,unless="#result==null"*/)
 public User find(User user) {
    return user;
 }

注意事项

  • SpringBoot启动类开启@EnableCaching

  • A class 调用 B class 的@Cacheable的方法,一定是public方法

  • A class 调用 B class 的@Cacheable的方法,B 一定是@Component、@Service等

  • B class 的@Cacheable的方法xx1调用@Cacheable的方法xx2,B缓存不起作用。解决方案:Spring上下文手动获取Bean实例调用xx2,或者AopContext.currentProxy())调用xx2,不过ApoContenxt这个,需要在启动累开启@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

  • 开启@EnableCache,注意区分Redis的CacheManager,在注解通过指定@Cacheable(cacheManager=“caffeineCacheManager”,…)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值