基于guava实现本地缓存

今天一个接口响应超时,然后我优化,用到了本地缓存。

maven 依赖

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.1-jre</version>
    </dependency>

 

LocalCache 本地缓存工具类

package com.itbac.common.cache;

import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;



/**
 * 本地缓存工具
 *
 * <br/>对于一些改动频率低且调用非常频繁,可加上本地有效时间短(1分钟)的二级缓存
 *
 * @author Bac
 *
 * @Date 2020年1月6日 下午12:12:12
 */
public class LocalCache<K,V> {

    /**默认的本地缓存最大数据长度*/
    private static final long Default_Maximum_Size = 5_000;
    /**本地缓存数据长度为1    */
    private static final long Single_Size = 1;

    /**写入本地缓存后的失效时间秒数*/
    private static final long Max_Expire_After_Write = 1 * 60;


    private Cache<K, Optional<V>> cache;

    private LocalCache(){}

    /**
     * 创建本地缓存对象(创建此对象后,需要用static成员变量进行唯一初始化引用)
     * (默认为一分钟缓存)
     * @return
     */
    public static <K,V> LocalCache<K,V> create() {
        LocalCache<K,V> local = new LocalCache<K,V> ();

        local.cache =  CacheBuilder.newBuilder()
                .maximumSize(Default_Maximum_Size)
                .expireAfterWrite(Max_Expire_After_Write, TimeUnit.SECONDS)
                .build();
        return local;
    }

    /**
     * 创建本地缓存对象
     * @param expireAfterWrite 写入缓存后失效的秒数
     * @return
     */
    public static <K,V> LocalCache<K,V> create(long expireAfterWrite) {
        LocalCache<K,V> local = new LocalCache<K,V> ();

        local.cache =  CacheBuilder.newBuilder()
                .maximumSize(Default_Maximum_Size)
                .expireAfterWrite(expireAfterWrite <= 0 ?  Max_Expire_After_Write : expireAfterWrite, TimeUnit.SECONDS)
                .build();
        return local;
    }

    /**
     * 创建只能缓存一个数据元素的本地缓存对象
     * @return
     */
    public static <K,V> LocalCache<K,V> createSingleSize() {
        LocalCache<K,V> local = new LocalCache<K,V> ();

        local.cache =  CacheBuilder.newBuilder()
                .maximumSize(Single_Size)
                .expireAfterWrite(Max_Expire_After_Write, TimeUnit.SECONDS)
                .build();
        return local;
    }



    private Cache<K, Optional<V>> getCache() {
        return this.cache;
    }

    /**
     * 获取缓存k对应的值,没有值返回null
     * @param k       缓存key
     * @return
     */
    public Optional<V> get(K k) {
        return getCache().getIfPresent(k);
    }


    /**
     * 获取缓存key对应的值,若key未在本地缓存中,使用call进行初始化
     * @param k          缓存key
     * @param call    若key未在本地缓存中,使用call进行初始化。
     *                可用Lambada表达式, () ->{ 具体逻辑,return V };
     * @return
     */
    public V get(K k,Supplier<V> call) {
        if (k == null) {
            return null;
        }
        /**
         * 由于Guava的Callable接口中,若采用过期机制,
         * 如果自带的Callable返回了null,get(xx,CallAble)便会抛出异常: CacheLoader returned null for key
         * 故采用Optional + 额外的Supplier
         */
        Optional<V>  value = get(k);
        //未放置本地缓存数据
        if (value == null) {
            V v =  call.get();
            getCache().put(k, Optional.ofNullable(v));
            return v;
        }
        return value.orElse(null);
    }
}

使用本地缓存

package com.itbac.common.cache;

import java.util.ArrayList;
import java.util.List;


public class SkuQueryService {

    //本地缓存,写入后20秒失效
    private static final LocalCache<String, List<String>> Cache = LocalCache.create(20);

    public static void main(String[] args) {

        //使用本地缓存
        List<String> list = Cache.get("key", () -> {
            //具体获取数据的逻辑
            List<String> strings = new ArrayList<>();
            strings.add("假装有数据");
            return strings;
        });

    }
}

设置缓存后,要等到了时间,缓存才会失效。需要容忍一段时间的数据不一致。

posted @ 2020-01-06 23:57  北溪  阅读(1262)  评论(0编辑  收藏  举报