内存缓存Caffeine

Caffeine是什么?

Caffeine是使用Java8对Guava缓存的重写版本。大大改善了设计Guava's cache 和 ConcurrentLinkedHashMap 的体验。
Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架。

Guava Cache是什么?

Google Guava Cache是一种非常优秀本地缓存解决方案,提供了基于容量,时间和引用的缓存回收方式。

Caffeine能做什么?

数据缓存在jvm中,大幅提升性能

为什么要用本地缓存

相对于IO操作,速度快,效率高
相对于Redis,Redis是一种优秀的分布式缓存实现,受限于网卡等原因,远水救不了近火

本地缓存的缺点

节点重启、缓存丢失
无法大量存储,受限于jvm
集群多节点缓存不一致问题

什么时候使用

相同的结果被大量访问
愿意消耗一些内存空间来提升速度
缓存中存放的数据总量不会超出内存容量

主流缓存对比

Caffeine淘汰算法比较先进,并且得到 Spring Cache 的支持(新版的 Spring Cache 不再支持 Guava Cache)

spring2.x接入

第一步、添加依赖

<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.9.2</version>
</dependency>

第二步创建CaffeineCacheConfig.java

@Configuration
public class CacheConfig {

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

第三步、注入

@Autowired
Cache<String, Object> caffeineCache;

第四步、使用

####(1)添加到缓存
  caffeineCache.put("abc","def");

####(2)从缓存获取
  Object obj = caffeineCache.getIfPresent("abc");

####(3)从缓存获取,若获取不到,则调用createInfo("abc")加载到缓存,再返回结果
  Object o = caffeineCache.get("abc",k -> createInfo("abc"));

####(4)存入实体类
  caffeineCache.put("obj",new UserInfo(3,"cat"));
  Object obj2 = caffeineCache.getIfPresent("obj");
  UserInfo ui2 = (UserInfo)obj2;

####(5)存入List<String>
  List<String> strList = new ArrayList<>();
  strList.add("a");
  strList.add("b");
  strList.add("c");
  strList.add("d");
  caffeineCache.put("strList",strList);
  Object strListCache = caffeineCache.getIfPresent("strList");
  List<String> strList2 = (List<String>)strListCache;

####(6)存入List<UserInfo>
  //测试list
  List<UserInfo> objList = new ArrayList<>();
  objList.add(new UserInfo(3,"cat"));
  objList.add(new UserInfo(34,"cat4"));
  caffeineCache.put("objList",objList);
  Object objListCache = caffeineCache.getIfPresent("objList");
  List<String> objList2 = (List<String>)objListCache;

####(7)存入Map<String,List<UserInfo>>
  Map<String,List<UserInfo>> map = new HashMap<>();
  List<UserInfo> oneList = new ArrayList<>();
  oneList.add(new UserInfo(55,"bird"));
  map.put("11",oneList);

  List<UserInfo> twoList = new ArrayList<>();
  twoList.add(new UserInfo(55,"bird"));
  twoList.add(new UserInfo(56,"tomcat"));
  map.put("12",twoList);

  caffeineCache.put("map",map);
  Object mapCache = caffeineCache.getIfPresent("map");
  Map<String,List<UserInfo>> map2 = (Map<String,List<UserInfo>>)mapCache;

相关代码

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class UserInfo {

    public UserInfo(){}

    public UserInfo(int id ,String name){
        this.id = id;
        this.name = name;
    }

    private Integer id;
    private String name;
    private String sex;
    private Integer age;
}
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Caffeine是使用Java8对Guava缓存的重写版本
 *
 * 在Spring Boot 2.0中将取代Guava。如果出现Caffeine,CaffeineCacheManager将会自动配置。
 *
 * DB + Redis + LocalCache = 高效存储,高效访问
 *
 *
 * 什么时候用?
 * 愿意消耗一些内存空间来提升速度
 * 预料到某些键会被多次查询
 * 缓存中存放的数据总量不会超出内存容量
 *
 *
 * 可以做什么?
 * 设置缓存容量
 * 设置超时时间
 * 提供移除监听器
 * 提供缓存加载器
 * 构建缓存
 *
 *
 * spring2.x只需要引入
 * <dependency>
 *      <groupId>com.github.ben-manes.caffeine</groupId>
 *      <artifactId>caffeine</artifactId>
 * </dependency>
 *
 *
 * initialCapacity=[integer]: 初始的缓存空间大小
 * maximumSize=[long]: 缓存的最大条数
 * maximumWeight=[long]: 缓存的最大权重
 * expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
 * expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
 * refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
 * weakKeys: 打开key的弱引用
 * weakValues:打开value的弱引用
 * softValues:打开value的软引用
 * recordStats:开发统计功能
 * 注意:
 * expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。
 * maximumSize和maximumWeight不可以同时使用
 * weakValues和softValues不可以同时使用
 *
 */
@Configuration
public class CacheConfig {

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


}
package com.example.alldemo.me.util.cache.guava;

import com.github.benmanes.caffeine.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/cache")
public class UserInfoController {

    @Autowired
    Cache<String, Object> caffeineCache;



    public Object createInfo(String key){
        return "大老虎一只";
    }

    public void test() {
        log.info("enter test");

        Object obj = caffeineCache.getIfPresent("abc");
        log.info("abc is [" + obj + "].");


        Object o = caffeineCache.get("abc",k -> createInfo("abc"));


        caffeineCache.put("abc","def");
        obj = caffeineCache.getIfPresent("abc");
        if(obj != null){
            log.info("abc is [" + obj.toString() + "].");
        }




        //测试Object
        caffeineCache.put("obj",new UserInfo(3,"cat"));
        Object obj2 = caffeineCache.getIfPresent("obj");
        UserInfo ui2 = (UserInfo)obj2;


        //测试list<String>
        List<String> strList = new ArrayList<>();
        strList.add("a");
        strList.add("b");
        strList.add("c");
        strList.add("d");
        caffeineCache.put("strList",strList);
        Object strListCache = caffeineCache.getIfPresent("strList");
        List<String> strList2 = (List<String>)strListCache;

        //测试list
        List<UserInfo> objList = new ArrayList<>();
        objList.add(new UserInfo(3,"cat"));
        objList.add(new UserInfo(34,"cat4"));
        caffeineCache.put("objList",objList);
        Object objListCache = caffeineCache.getIfPresent("objList");
        List<String> objList2 = (List<String>)objListCache;





        //测试map
        Map<String,List<UserInfo>> map = new HashMap<>();

        List<UserInfo> oneList = new ArrayList<>();
        oneList.add(new UserInfo(55,"bird"));
        map.put("11",oneList);

        List<UserInfo> twoList = new ArrayList<>();
        twoList.add(new UserInfo(55,"bird"));
        twoList.add(new UserInfo(56,"tomcat"));
        map.put("12",twoList);


        caffeineCache.put("map",map);
        Object mapCache = caffeineCache.getIfPresent("map");
        Map<String,List<UserInfo>> map2 = (Map<String,List<UserInfo>>)mapCache;




        log.info("exit test");
    }

}
原文地址:https://www.cnblogs.com/jis121/p/15656757.html