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

一、引入依赖

 <dependency>
     <groupId>com.github.ben-manes.caffeine</groupId>
     <artifactId>caffeine</artifactId>
     <version>2.8.8</version>
 </dependency>
  • caffeine3.x版本不支持jdk1.8,所以这里选用2.8.8

二、自定义枚举

一个项目里可能需要缓存的数据有很多,比如用户信息,权限信息,菜单信息等等,我们需要给不同的场景分配不同的命名空间,并设置不同的过期时间

public enum CacheEnum {
    /**
     * 用户缓存,缓存时间单位/秒
     */
    CACHE_USERS("users", 2),
    /**
     * 菜单缓存,缓存时间单位/秒
     */
    CACHE_MENU("menu", 2),
    ;
    /**
     * 缓存名称
     */
    private final String name;
    /**
     * 过期时间
     */
    private final int expires;

}

三、缓存配置类

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

注意:

  • expireAfterWriteexpireAfterAccess同事存在时,以expireAfterWrite为准。
  • maximumSizemaximumWeight不可以同时使用
  • weakValuessoftValues不可以同时使用

如果是在自定义的starter里,还需要在MATE-INFO/spring.factories中配置EnableAutoConfiguration

四、工具类

public enum CacheUtil {
    
    /**
    * 工具类标记
    */
    X;
    
    private final CacheManager cm;

    CacheUtil() {
        cm = SpringUtil.getBean("cacheManager", CacheManager.class);
    }

    /**
     * 添加缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     * @param value     缓存值
     */
    public void put(String cacheName, String key, Object value) {
        Cache cache = cm.getCache(cacheName);
        cache.put(key, value);
    }

    /**
     * 获取缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     * @return
     */
    public <T> Optional<T> get(String cacheName, String key) {
        Cache cache = cm.getCache(cacheName);
        if (cache == null) {
           return Optional.empty();
        }
        Cache.ValueWrapper valueWrapper = cache.get(key);
        if (null == valueWrapper) {
            return Optional.empty();
        }
        return  Optional.of((T) valueWrapper.get());
    }

    /**
     * 失效缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     */
    public void evict(String cacheName, String key) {
        Cache cache = cm.getCache(cacheName);
        if (cache != null) {
            cache.evict(key);
        }
    }
}
  • 工具类需要保证都是单例的,而枚举类天然支持单例,X表示工具类
  • 获取缓存使用Optional作为返回,是为了提醒使用者可能返回null的情况,需要做针对处理

五、单元测试

    @Test
    public void test_cache_put() throws InterruptedException {
        CacheUtil.X.put(CacheEnum.CACHE_USERS.getName(), "users", "zhangsan");
        CacheUtil.X.put(CacheEnum.CACHE_MENU.getName(), "menus", Arrays.asList("1", "2", "3", "4"));

        Optional<String> users = CacheUtil.X.get(CacheEnum.CACHE_USERS.getName(), "users");
        if (users.isPresent()) {
            String str = users.get();
            System.out.println(str);
        }
        Optional<List<String>> menus = CacheUtil.X.get(CacheEnum.CACHE_MENU.getName(), "menus");
        menus.ifPresent(System.out::println);

        // 测试缓存过期情况
        Thread.sleep(2000);
        Optional<String> users2 = CacheUtil.X.get(CacheEnum.CACHE_USERS.getName(), "users");
        if (users2.isPresent()) {
            String str = users2.get();
            System.out.println(str);
        }
        Optional<List<String>> menus2 = CacheUtil.X.get(CacheEnum.CACHE_MENU.getName(), "menus");
        menus2.ifPresent(System.out::println);
    }

最强本地缓存Caffeine的更多相关文章

  1. 解读JVM级别本地缓存Caffeine青出于蓝的要诀 —— 缘何会更强、如何去上手

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 在前面的几篇文章中,我们一起聊了下本地 ...

  2. 解读JVM级别本地缓存Caffeine青出于蓝的要诀3 —— 讲透Caffeine的数据驱逐淘汰机制与用法

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中,我们聊了下Caffein ...

  3. 本地缓存Caffeine

    Caffeine 说起Guava Cache,很多人都不会陌生,它是Google Guava工具包中的一个非常方便易用的本地化缓存实现,基于LRU算法实现,支持多种缓存过期策略.由于Guava的大量使 ...

  4. 解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中,我们继Guava Cac ...

  5. springboot之本地缓存(guava与caffeine)

    1. 场景描述 因项目要使用本地缓存,具体为啥不用redis等,就不讨论,记录下过程,希望能帮到需要的朋友. 2.解决方案 2.1 使用google的guava作为本地缓存 初步的想法是使用googl ...

  6. Caffeine Cache-高性能Java本地缓存组件

    前面刚说到Guava Cache,他的优点是封装了get,put操作:提供线程安全的缓存操作:提供过期策略:提供回收策略:缓存监控.当缓存的数据超过最大值时,使用LRU算法替换.这一篇我们将要谈到一个 ...

  7. 本地缓存解决方案-Caffeine Cache

    1.1 关于Caffeine Cache ​ Google Guava Cache是一种非常优秀本地缓存解决方案,提供了基于容量,时间和引用的缓存回收方式.基于容量的方式内部实现采用LRU算法,基于引 ...

  8. spring boot: 用redis的消息订阅功能更新应用内的caffeine本地缓存(spring boot 2.3.2)

    一,为什么要更新caffeine缓存? 1,caffeine缓存的优点和缺点 生产环境中,caffeine缓存是我们在应用中使用的本地缓存, 它的优势在于存在于应用内,访问速度最快,通常都不到1ms就 ...

  9. spring boot:使用spring cache+caffeine做进程内缓存(本地缓存)(spring boot 2.3.1)

    一,为什么要使用caffeine做本地缓存? 1,spring boot默认集成的进程内缓存在1.x时代是guava cache 在2.x时代更新成了caffeine, 功能上差别不大,但后者在性能上 ...

  10. Java高性能本地缓存框架Caffeine

    一.序言 Caffeine是一个进程内部缓存框架,使用了Java 8最新的[StampedLock]乐观锁技术,极大提高缓存并发吞吐量,一个高性能的 Java 缓存库,被称为最快缓存. 二.缓存简介 ...

随机推荐

  1. 基于新浪微博海量用户行为数据、博文数据数据分析:包括综合指数、移动指数、PC指数三个指数

    基于新浪微博海量用户行为数据.博文数据数据分析:包括综合指数.移动指数.PC指数三个指数 项目介绍 微指数是基于海量用户行为数据.博文数据,采用科学计算方法统计得出的反映不同事件领域发展状况的指数产品 ...

  2. 深度学习应用篇-计算机视觉-视频分类[8]:时间偏移模块(TSM)、TimeSformer无卷积视频分类方法、注意力机制

    深度学习应用篇-计算机视觉-视频分类[8]:时间偏移模块(TSM).TimeSformer无卷积视频分类方法.注意力机制 1.时间偏移模块(TSM) 视频流的爆炸性增长为以高精度和低成本执行视频理解任 ...

  3. C/C++ 实现Socket交互式服务端

    在 Windows 操作系统中,原生提供了强大的网络编程支持,允许开发者使用 Socket API 进行网络通信,通过 Socket API,开发者可以创建.连接.发送和接收数据,实现网络通信.本文将 ...

  4. 算法与数据结构-07-手写类HashTable

    package day05; import java.sql.SQLOutput; import java.util.Scanner; /** * 哈希表代码实现 */ public class Ha ...

  5. Docker从认识到实践再到底层原理(二-1)|容器技术发展史+虚拟化容器概念和简介

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...

  6. static_cast, dynamic_cast与reinterpret_cast的区别

    在C++中,static_cast, dynamic_cast和reinterpret_cast都可用于类型转换,它们在具体使用时有什么区别?此外,更为重要的是,为什么不推荐使用强制类型转换? 1. ...

  7. 蓝鲸:主机频繁提示“You have new mail in /var/spool/mail/root” 定位解决

    前些天安装蓝鲸的测试环境频繁出现You have new mail in /var/spool/mail/root,查看发现是/usr/local/gse/agent/bin/gsectl: line ...

  8. 推荐一款id生成器: Hashids

    唯一 id 生成的方式有很多种,比较常见的有以下几种方式: 语言自带功能,如 Java 中的 UUID,常用于后端 第三方工具提供,如 npm 中的 nanoid,常用于前端 Twitter 开源的 ...

  9. CF1089K King Kog's Reception 题解

    题目传送门 前置知识 线段树 解法 第一眼感觉和 luogu P1083 [NOIP2012 提高组] 借教室 很像.本题同样采用线段树维护,\(sum_{l,r}(1 \le l \le r \le ...

  10. NC19857 最后的晚餐(dinner)

    题目链接 题目 题目描述 ​ **YZ(已被和谐)的食堂实在是太挤辣!所以Apojacsleam现在想邀请他的一些好友去校外吃一顿饭,并在某酒店包下了一桌饭. ​ 当Apojacsleam和他的同学们 ...