Caffeine cache实现本地缓存(简单又清楚)

缓存填充策略

介绍:缓存的填充方式有三种,手动、同步和异步

 手动加载

 介绍:

手动控制缓存的增删改处理,主动增加、获取以及依据函数式更新缓存,底层使用ConcurrentHashMap进行节点存储,因此get方法是安全的。批量查找可以使getAllPresent()方法或者带填充默认值的getAll()方法

 使用方式:
@Test
void test1() {
  com.github.benmanes.caffeine.cache.@NonNull Cache<String, String> cache = Caffeine.newBuilder()
       // 最大数量
       .maximumSize(100)
       // 设置缓存策略在1天未写入过期缓存
       .expireAfterAccess(1, TimeUnit.DAYS)
       .build();
  // 存入缓存
  cache.put("cl", "cl");
  // 根据键值获取缓存
  System.out.println(cache.getIfPresent("cl"));
  // 根据键值获取缓存, 如果为空则调用后面的参是
  System.out.println(cache.get("abc", this::buildLoader));
  // 根据键值清除缓存
  cache.invalidate("abc");
  System.out.println(cache.getIfPresent("abc"));
}
// 缓存后面执行的方法
 String buildLoader(String k) {
  return k + "+default";
}

 同步加载

 介绍:

LoadingCache对象进行缓存的操作,使用CacheLoader进行缓存存储管理。 批量查找可以使用getAll()方法。 默认情况下, getAll()将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值(build中的表达式)。我们可以重写CacheLoader.loadAll方法来提高getAll()的效率。

 使用方式:
@Test
void test1() {
    LoadingCache<String, String> loadingCache = Caffeine.newBuilder()
         .maximumSize(100)
         .expireAfterAccess(1, TimeUnit.DAYS)
         // getAll将会对缓存中, 没有值的key分别调用CacheLoader.load方法来构建缓存的值
          .build(this :: buildLoader);
    // 存储要添加的缓存
     List<String> keys = new ArrayList<>();
    keys.add("cl");
    keys.add("b");
    keys.add("c");
    keys.add("d");
    // 返回一个map
    Map<String, String> cacheAll = loadingCache.getAll(keys);
    System.out.println(cacheAll.get("b"));
    System.out.println(cacheAll.get("c"));
    System.out.println(cacheAll.get("a"));
}
// 缓存后面执行的方法
 String buildLoader(String k) {
  return k + "+default";
}
 

 异步加载

 介绍:

AsyncLoadingCache对象进行缓存管理,get()返回一个CompletableFuture对象,默认使用ForkJoinPool.commonPool()来执行异步线程,但是我们可以通过Caffeine.executor(Executor) 方法来替换线程池
在这里插入图片描述

  注意: 异步和同步使用方式相似, 这里的话主要写一下创建和异步转同步
 使用方式:
@Test
void test1() {
  AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
       .maximumSize(100)
       .expireAfterAccess(1,TimeUnit.DAYS)
       .buildAsync(k-> this.buildLoaderAsync(k).get());

  try {
    System.out.println(asyncLoadingCache.get("123").get());
  } catch (Exception e) {
    e.printStackTrace();
  }
}
// 类似同步的load
CompletableFuture<String> buildLoaderAsync(String k) {
  return CompletableFuture.supplyAsync(() -> k + "buildLoaderAsync");
}
转换使用方式:
AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
    .maximumSize(100)
    .expireAfterAccess(1,TimeUnit.DAYS)
    .buildAsync(k -> this.buildLoaderAsync(k).get());
// 异步转同步
LoadingCache<String, String> cache = asyncLoadingCache.synchronous();
System.out.println("------------");
System.out.println(cache.get("dd")); 

过期策略

介绍:

Caffeine的缓存清除是惰性的,可能发生在读请求后或者写请求后
比如说有一条数据过期后,不会立即删除,可能在下一次读/写操作后触发删除(类比于redis的惰性删除)。
如果读请求和写请求比较少,但想要尽快的删掉cache中过期的数据的话,
可以通过增加定时器的方法,定时执行cache.cleanUp()方法(异步方法,可以等待执行),触发缓存清除操作。

 基于大小过期

  介绍:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理
  使用方式:
  maximumSize()方法,参数是缓存中存储的最大缓存条目,当添加缓存时达到条目阈值后,将进行缓存淘汰操作
  // 使用方式 
    AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
       .maximumSize(100)

 基于权重过期

  介绍:

通过权重来计算,每个实体都有不同的权重,总权重到达最高时淘汰实体。
weigher()方法可以指定缓存所占比重,maximumWeight()方法指定最大的权重阈值,当添加缓存超过规定权重后,进行数据淘汰

  使用方式:
com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder()
    .maximumWeight(10)
    .weigher(new Weigher<Object, Object>() {

       @Override
       public @NonNegative int weigh(@NonNull Object o, @NonNull Object o2) {
         System.out.println("key" + o + "value" + o2);
         return 5;
       }
    })
    .build(this::buildLoader);
List<String> list = Lists.newArrayList("c1", "c2", "c3");
cache.put(list.get(0), list.get(0));
System.out.println(list.get(0) + "--" + cache.get(list.get(0)));
cache.put(list.get(1), list.get(1));
System.out.println(list.get(1) + "---" + cache.get(list.get(1)));
System.out.println(cache.getAll(list));

 基于时间过期

  介绍:

expireAfterAccess():缓存访问后,一定时间失效;即最后一次访问或者写入开始时计时。
expireAfterWrite():缓存写入后,一定时间失效;以写入缓存操作为准计时。(在最后一次写入缓存后开始计时,在指定的时间后过期。)
expireAfter():自定义缓存策略,满足多样化的过期时间要求。
这里只展示after, 其他的话 使用方式大致相同,自己动手试试
注意:当expireAfterAccess和expireAfterWrite同时存在时,只有expireAfterWrite有效

  使用方式:
com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder()
    .expireAfter(new Expiry<Object, Object>() {
       // 创建后过期
       @Override
       public long expireAfterCreate(@NonNull Object o, @NonNull Object o2, long l) {
         return 1;
       }
       // 更新后过期
       @Override
       public long expireAfterUpdate(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {
         return 1;
       }
       // 读取后过期
       @Override
       public long expireAfterRead(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {
         return 1;
       }
    }).build(this::buildLoader);
 

 基于引用回收

  介绍:

在这里插入图片描述

  使用方式:

在这里插入图片描述

基本使用

 手动删除

  使用方式:

在这里插入图片描述

 自动刷新

  使用方式:

refreshAfterWrite:这里设置的是1分钟后自动刷新
在这里插入图片描述

 移除通知

  使用方式:

在这里插入图片描述

 外部存储

  使用方式:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 统计缓存使用情况

  使用方式:

在这里插入图片描述

实例整合

 编码方式

  使用方式:

1、缓存配置类

@Configuration
public class CacheConfig {
  @Bean
  public Cache<String, Object> caffeineCache() {
    return Caffeine.newBuilder()
         // 设置最后一次写入或访问后经过固定时间过期
          .expireAfterWrite(60, TimeUnit.SECONDS)
         // 初始的缓存空间大小
          .initialCapacity(100)
         // 缓存的最大条数
          .maximumSize(1000)
         .build();
  }
}

2、使用
注意:这里我只写了存入的写法, 如果要获取缓存,用cache的get缓存我们存储的key就可以了。
如:

// 以下代码的具体含义请看文章, 文章都有介绍,如果没有 可以评论 我会给你进行解答
cache.put(1,"测试缓存")
// 获取缓存
cache.get("1");
// 如果你使用get爆红, 那可能是因为你没有填写第二个,那么你可以这样做
cache.get("1", value -> value);
// 或者
cache.asMap().get("1");

示例:

private final Cache<Object, Object> cache;
public FeedbackServiceImpl( Cache<Object, Object>  cache) {
  this.cache = cache;
}
public void insertFeedBack(Feedback feedback) {
  int i = feedbackMapper.insert(feedback);
  cache.put(feedback.getId(), feedback);
}

注意:如果你只是简单的使用, 你可以使用末文的缓存工具类

 注解方式(整合SpringBoot的cache)

  介绍:

在这里插入图片描述
在这里插入图片描述

  使用方式:
   @Cacheable注解:

在这里插入图片描述

   @CachePut注解:

在这里插入图片描述

   @CacheEvict注解:

在这里插入图片描述

   @CacheConfig注解:
// 一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用
@CacheConfig(cacheNames="emp") //抽取缓存的公共配置
   @Caching注解:

在这里插入图片描述

示例:

// 开启缓存
@EnableCaching
public class Springboot01CacheApplication {
 
  public static void main(String[] args) {
     SpringApplication.run(Springboot01CacheApplication.class, args);
  }
}
 // 其他方法使用和他一样, 具体可以看代码,来自己动动手试试看
 @Cacheable(cacheNames = {"emp"},condition = "#id>0")
        public Employee getEmp(Integer id){
            System.out.println("查询"+id+"号员工");
            Employee emp = employeeMapper.getEmpById(id);
            return emp;
        }

简易缓存工具类

 具体含义看代码注释

/**
 * @author huangye  所谓致知在格物者,言欲致吾之知,在即物而穷其理也。
 * @version 1.0  2020/10/4
 */
public class CacheUtil{

	private static  Cache<String, Object> cache;

	static {
		cache = createCache();
	}

	/**
	 * 插入缓存 | 更新缓存
	 * @param cacheName 缓存前缀
	 * @param key 键
	 * @param value 值
	 */
	public static void saveCache(String cacheName, String key, Object value) {
		System.out.printf("存储缓存的数据 key(%s) value(%s)",cacheName + "-" + key, value);
		System.out.println();
		cache.asMap().put(cacheName + "-" + key, value);
	}

	/**
	 * 根据键获取缓存
	 * @param cacheName 缓存前缀
	 * @param key 键
	 * @return Object类型, 由使用者自己转换
	 */
	public static Object getCache(String cacheName, String key) {
		System.out.printf("获取缓存的数据 key(%s) value(%s)",cacheName + "-" + key,
				cache.asMap().get(cacheName + "-" + key) );
		System.out.println();
		return cache.asMap().get(cacheName + "-" + key);
	}

	/**
	 * 根据键值删除缓存
	 * @param cacheName 缓存前缀
	 * @param key 建
	 */
	public static void deleteCache(String cacheName, String key) {
		System.out.printf("删除缓存的数据 key(%s)", cacheName + "-" + key);
		System.out.println();
		cache.asMap().remove(cacheName + "-" + key);
	}

	private static class CacheSingletonHolder {
		private final static Cache<String, Object> CACHE = Caffeine.newBuilder()
				// 初始的缓存空间大小
				.initialCapacity(100)
				// 缓存的最大条数
				.maximumSize(1000)
				// 最后一次缓存访问过后,7天后失效
				.expireAfterAccess(7, TimeUnit.DAYS)
				.build();
	}
	 private static Cache<String, Object> createCache() {
		return CacheSingletonHolder.CACHE;
	}
}

ps:这里的图片都来源于我学习时做的笔记(下图位证), 因为有的是在网上找文章学习的,所以可能会遇到有的是和别人一样的内容,我是想着吧那些之前看的文章放到文章末尾的,但是我找不到了非常抱歉, 我这里的话只是想做个知识的汇总,如果有错误的地方,可以评论留言 我会改正,谢谢
在这里插入图片描述

  • 12
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值