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. C++ LibCurl实现Web隐藏目录扫描

    LibCurl是一个开源的免费的多协议数据传输开源库,该框架具备跨平台性,开源免费,并提供了包括HTTP.FTP.SMTP.POP3等协议的功能,使用libcurl可以方便地进行网络数据传输操作,如发 ...

  2. 用npm查看可安装的包版本

    1.查看包版本命令 npm view less-loader versions

  3. 自己封装的 Python 常用工具库(prestool)

    一.安装 需Python 版本建议 3.7 以上 pip install --upgrade prestool 二.常用工具 from prestool.Tool import Tool tool = ...

  4. ListView改变行高的技巧

    改变 ListView 的行高 (Line Height) (cjc,2009.6.2) 改变 ListView 的行高 (Line Height) (cjc,2009.6.2) ListView在R ...

  5. [pwn之路]patchelf之后,加载符号表!

    # 前言 当你在进行二进制漏洞学习和利用时,经常需要使用调试工具来分析和理解程序的内部工作.在之前的交流中,我们提到了如何使用patchelf来修改二进制文件[Pwn之路]根据所给库,获得远程同环境- ...

  6. Linux查看系统版本的方法

    记录几种查看当前Linux系统的版本的方法 一.使用命令:cat /proc/version 查看 linux版本号:Linux version 5.4.0-99-generic (buildd@lg ...

  7. mysql 外键索引入门介绍,为什么工作中很少有人使用?

    背景 以前工作学习中,一直被告诫不要使用外键,所以也没有仔细整理过. 这里记录一下笔记. 外键 是什么? MySQL 的外键(Foreign Key)是一种关系型数据库中用于建立表与表之间关联关系的重 ...

  8. seq2seq模型案例分析

    1 seq2seq模型简介 seq2seq 模型是一种基于[ Encoder-Decoder](编码器-解码器)框架的神经网络模型,广泛应用于自然语言翻译.人机对话等领域.目前,[seq2seq+at ...

  9. 解决SQLyog连接mysql报错:Your password has expired

    解决步骤如下: D:\program\mysql-5.7.16-winx64\bin>mysql -uroot -p Enter password: ******* Welcome to the ...

  10. RestTemplate的一些坑和改造点

    一.RestTemplate怎么引入和使用 在pom.xml文件中加入如下dependency: <dependency> <groupId>org.springframewo ...