java缓存——(二) Caffeine缓存CacheManager与配置文件

Spring boot Caffeine缓存(一)——CacheManager与配置文件
Spring boot Caffeine缓存(二)——Cache、LoadingCache
Spring boot Caffeine缓存(三)——使用注解
spring5(springboot2)开始用Caffeine取代guava,至于其性能对比可以参考Caffeine给的测试结果各缓存性能对比
这里贴出一个读写的对比

Caffeine在springboot中集成非常简单,可以通过配置文件来设置

spring:
  cache:
    cache-names: outLimit,notOutLimit
    caffeine:
      spec: initialCapacity=50,maximumSize=500,expireAfterWrite=5s,refreshAfterWrite=7s
    type: caffeine

这种方法设置的简单,但是灵活性不够高,如上边设置的cache(cache name)所有的规则都是一样的。这块我没深入研究,不多做介绍。

也可以通过代码配置 

左边这块是我在看Caffeine时做的一些配置。这些东西很多,我可能会分多篇文章来讲。

先来说下最常用的CacheManager

CacheManager
CacheManager的使用场景比较多,最常见的@Cacheable、@CachePut、@CacheEvict等默认都可以配合CacheManager使用。

先看下我集成的三个CacheManager

@Value("${caffeine.spec}")
    private String caffeineSpec;

    @Autowired
    private CacheLoader cacheLoader;


    @Bean
    public CacheManager cacheManagerWithCacheLoading(){
        logger.info("cacheManagerWithCacheLoading" );
        Caffeine caffeine = Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(1000)
//                .refreshAfterWrite(5,TimeUnit.SECONDS)
                .expireAfterWrite(50,TimeUnit.SECONDS);

        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setAllowNullValues(true);
        cacheManager.setCaffeine(caffeine);
//        cacheManager.setCacheLoader(cacheLoader);
        cacheManager.setCacheNames(getNames());
        return cacheManager;
    }



    @Bean(name = "caffeine")
    @Primary
    public CacheManager cacheManagerWithCaffeine(){
        logger.info("This is cacheManagerWithCaffeine");
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        Caffeine caffeine = Caffeine.newBuilder()
                //cache的初始容量值
                .initialCapacity(100)
                //maximumSize用来控制cache的最大缓存数量,maximumSize和maximumWeight不可以同时使用,
                .maximumSize(1000);
                //控制最大权重
//                .maximumWeight(100);
//                .expireAfter();
                //使用refreshAfterWrite必须要设置cacheLoader
//                .refreshAfterWrite(5,TimeUnit.SECONDS);
        cacheManager.setCaffeine(caffeine);
//        cacheManager.setCacheLoader(cacheLoader);
        cacheManager.setCacheNames(getNames());
//        cacheManager.setAllowNullValues(false);
        return cacheManager;
    }

    @Bean(name = "caffeineSpec")
    public CacheManager cacheManagerWithCaffeineFromSpec(){
        CaffeineSpec spec = CaffeineSpec.parse(caffeineSpec);
        Caffeine caffeine = Caffeine.from(spec);
        //此方法等同于上面from(spec)
//        Caffeine caffeine = Caffeine.from(caffeineSpec);

        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeine);
        cacheManager.setCacheNames(getNames());
        return cacheManager;
    }

    private static List<String> getNames(){
        List<String> names = new ArrayList<>(2);
        names.add("outLimit");
        names.add("notOutLimit");
        return names;
    }

CacheLoader会在后面介绍,它是cache的一种加载策略,key不存在或者key过期之类的都可以通过CacheLoader来获得/重新获得数据。

cacheManagerWithCaffeine这个bean是以Caffeine为基础来设置一个CacheManager。如果设置refreshAfterWrite的话后边必须要设置cacheLoader。如果不设置的话,项目启动的时候会抛异常。
这里有个setCacheNames,主要是用来创建多个cache的,但是多个cache使用相同的策略。

cacheManagerWithCacheLoading这个bean是创建了一个带有CacheLoader的bean。它跟cacheManagerWithCaffeine这块的主要区别是,最初我在cacheManagerWithCaffeine里只是想创建一个简单的key-value存储,没有CacheLoader模块,所以cacheManagerWithCaffeine这个bean如果里边的key过期或不存在cache中是获取不到数据的,直接返回null。但是cacheManagerWithCacheLoading不同,如果key过期或不存在会从他的CacheLoader策略里重新加载数据。

cacheManagerWithCaffeineFromSpec是通过spec来创建cacheManager。
先看下面两行代码

 CaffeineSpec spec = CaffeineSpec.parse(caffeineSpec);
        Caffeine caffeine = Caffeine.from(spec);

caffeineSpec这里是从配置文件中获取的配置,如配置文件设置如下

caffeine:
  spec: initialCapacity=50,maximumSize=500,expireAfterWrite=5s

caffeineSpec是个符合其规则的字符串。 
进入其源码

 

@SuppressWarnings("StringSplitter")
  public static CaffeineSpec parse(String specification) {
    CaffeineSpec spec = new CaffeineSpec(specification);
    for (String option : specification.split(SPLIT_OPTIONS)) {
      spec.parseOption(option.trim());
    }
    return spec;
  }

可以看到其处理方式,非常简单。
Caffeine caffeine = Caffeine.from(spec);这行就是加载spec中的信息,自己点击下就知道什么意思了。

代码中写了很多注释,这里不多做解释了,如果有不明白的可以留言,或者在后边我会介绍其它块的时候点出。

代码的github地址Caffeine。这只是我自己摸索的时候写的,有些不太规范,仅供大家参考。
---------------------
原文:https://blog.csdn.net/qq_35981283/article/details/82354081

 

posted @ 2018-11-05 11:41  舞羊  阅读(2646)  评论(0编辑  收藏  举报