最强本地缓存Caffeine

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);
    }
posted @ 2024-03-09 17:48  孙半仙人  阅读(164)  评论(0编辑  收藏  举报