函数式编程+泛型实现本地缓存工具

125 阅读1分钟

一、前言

本地缓存大致流程可为:根据cacheKey去guava中查询数据,若存在,直接返回;若不存在,再去redis/mysql中查询,并把数据存到guava中......

可通过编写cacheUtil,把上述操作封装成一个方法,可供domain层任意处调用。虽然guava的key、value都是string类型,但我们封装的统一get方法的返回值是要string序列化之后的对象。为了满足不同返回值类型都能够使用封装完的get方法,可使用函数式编程 + 泛型进行编写。

二、CacheUtil

@Component
public class CacheUtil<V> {

    private Cache<String, String> localCache = CacheBuilder.newBuilder()
            .maximumSize(5000) //最大容量
            .expireAfterWrite(10, TimeUnit.SECONDS) //最大容量、过期时间
            .build();

    /**
     * @param cacheKey 缓存key
     * @param clazz 声明json序列化类型
     * @param function 由调用方自己写具体方法
     * @return
     */
    public List<V> getResult(String cacheKey, Class<V> clazz, Function<String, List<V>> function) {
        String content = localCache.getIfPresent(cacheKey);
        if(StringUtils.isNotBlank(content)) {
            return JSON.parseArray(content, clazz);
        }
        List<V> resultList = function.apply(cacheKey);
        if(!CollectionUtils.isEmpty(resultList)) {
            localCache.put(cacheKey, JSON.toJSONString(resultList));
        }
        return resultList;
    }

}

三、外部调用

    @Override
    @SneakyThrows
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        String cacheKey = "categoryAndLabel." + subjectCategoryBO.getId();
//        List<SubjectCategoryBO> resultList = cacheUtil.getResult(cacheKey, SubjectCategoryBO.class, new Function<String, List>() {
//            @Override
//            public List apply(String key) {
//                return getSubjectCategoryBOS(subjectCategoryBO.getId());
//            }
//        });
        List<SubjectCategoryBO> resultList = cacheUtil.getResult(cacheKey, SubjectCategoryBO.class, 
        (key) -> getSubjectCategoryBOS(subjectCategoryBO.getId()));
        return resultList;
    }

只有第一次调用 和 超时10s后调用会控制台打印出sql, 10s内调用会返回guava中的数据,不走mysql