• Caffeine 缓存库


    介绍

    Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库。

    缓存和ConcurrentMap有点相似,但还是有所区别。最根本的区别是ConcurrentMap将会持有所有加入到缓存当中的元素,直到它们被从缓存当中手动移除。
    但是,Caffeine的缓存Cache 通常会被配置成自动驱逐缓存中元素,以限制其内存占用。在某些场景下,LoadingCache和AsyncLoadingCache 因为其自动加载缓存的能力将会变得非常实用。

    基本使用

    GitHub 官方文档:https://github.com/ben-manes/caffeine/wiki/Home-zh-CN

    项目集成

    使用 Caffeine 作为一级缓存,Redis 作为二级缓存。先从 Caffeine 读取缓存,如果读不到则到 Redis 中读取,如果还没有则返回 null.
    模块使用了 Redis 作为二级缓存,使用 stringRedisTemplate 模板,Jedis 作为客户端。

    Spring 配置

    @Configuration
    public class Config {
        @Bean
        public AbstractStringFirstCache stringFirstCache() {
        	// 可以随意更换底层实现,比如我们可以使用 Guava Cache,只需要 new GuavaCache() 并继承 AbstractStringFirstCache 即可
            return new CaffeineCache();
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
            return new StringRedisTemplate(factory);
        }
    
        @Bean
        public JedisConnectionFactory redisConnectionFactory() {
            RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("localhost", 6379);
            return new JedisConnectionFactory(config);
        }
    }
    

    核心代码

    
    // 核心接口
    public interface FirstCache<K, V> {
        V get(@NonNull K key);
    
        void set(@NonNull K key, V value);
    
        void delete(@NonNull K key);
    }
    
    
    public abstract class AbstractFirstCache<K, V> implements FirstCache<K, V> {
    }
    
    
    public abstract class AbstractStringFirstCache extends AbstractFirstCache<String, String> {
        abstract void set(@NonNull String key, String value, Long expertTime, TimeUnit timeUnit);
    }
    
    
    public class CaffeineCache extends AbstractStringFirstCache {
    
        Log log = LogFactory.get(); //Hutool api
    
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
    
        LoadingCache<String, String> caffeineCache;
    
        public CaffeineCache() {
            LoadingCache<String, String> cache = Caffeine.newBuilder()
                    .recordStats()
                    .initialCapacity(100)
                    .maximumSize(1000)
                    .writer(new CacheWriter<String, String>() {
                        @Override
                        public void write(String key, String value) {
                            log.info("caffeineCache write key=" + key + ", value=" + value);
                        }
    
                        @Override
                        public void delete(String key, String value, RemovalCause cause) {
                            log.info("caffeineCache delete key=" + key);
                        }
                    })
                    .expireAfterWrite(30, TimeUnit.SECONDS) //一个元素将会在其创建或者最近一次被更新之后的一段时间后被认定为过期项
                    .build(new CacheLoader<String, String>() {
                        // 查询二级缓存
                        @Override
                        public @Nullable String load(@NonNull String s) throws Exception {
                            String value = stringRedisTemplate.opsForValue().get(s);
                            if (StrUtil.isEmpty(value)) {
                                return null;
                            }
                            return value;
                        }
                    });
            caffeineCache = cache;
        }
    
        @Override
        public String get(String key) {
            //查找缓存,如果缓存不存在则生成缓存元素
            String value = caffeineCache.get(key);
            log.info("get key from caffeineCache, key: " + key);
            return value;
        }
    
        @Override
        public void set(String key, String value) {
            //放入二级缓存
            stringRedisTemplate.opsForValue().set(key, value);
            stringRedisTemplate.expire(key, 15, TimeUnit.MINUTES);
        }
    
        @Override
        void set(String key, String value, Long expertTime, TimeUnit timeUnit) {
            stringRedisTemplate.opsForValue().set(key, value);
            stringRedisTemplate.expire(key, expertTime, timeUnit);
        }
    
        @Override
        public void delete(String key) {
            caffeineCache.invalidate(key);
            stringRedisTemplate.delete(key);
            log.info("delete key from caffeineCache, key: " + key);
        }
    }
    

    工具类

    @Component
    public class CaffeineCacheUtils {
    
        static AbstractStringFirstCache cache;
    
        @Autowired
        public void setCache(AbstractStringFirstCache cache) {
            CaffeineCacheUtils.cache = cache;
        }
    
        /**
         * 查找缓存,如果缓存不存在则生成缓存元素
         *
         * @return value or null
         */
        public static String get(@NonNull String key) {
            return cache.get(key);
        }
    
        /**
         * 设置缓存,默认 15min
         */
        public static void set(@NonNull String key, String value) {
            cache.set(key, value);
        }
    
        /**
         * 设置缓存,提供时间和时间单位
         */
        public static void set(@NonNull String key, String value, @NonNull Long expertTime, @NonNull TimeUnit timeUnit) {
            cache.set(key, value, expertTime, timeUnit);
        }
    
        /**
         * 删除缓存
         */
        public static void delete(@NonNull String key) {
            cache.delete(key);
        }
    }
    
  • 相关阅读:
    Linux ansible 常用模块二
    Linux之ansible 常用模块
    flask websocket实现用例
    flask--上下文原理
    python Django
    python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式
    并发编程 process 模块的方法及运用 僵尸与孤儿
    python 并发编程 操作系统 进程 并发.并行 及 同步/异步,阻塞/非阻塞
    python 网络编程粘包解决方案2 + ftp上传 + socketserver
    第一节 机器学习基础
  • 原文地址:https://www.cnblogs.com/manastudent/p/14342107.html
Copyright © 2020-2023  润新知