为了账号安全,请及时绑定邮箱和手机立即绑定

如何实现Guava缓存来存储和获取不同类型的对象?

如何实现Guava缓存来存储和获取不同类型的对象?

梵蒂冈之花 2022-01-06 19:57:45
现在我的缓存如下所示:public class TestCache {    private LoadingCache<String, List<ObjectABC>> cache;    TestCache() {        cache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(25)                .build(new CacheLoader<String, List<ObjectABC>>(                ) {                    @Override                    public List<ObjectABC> load(String key) throws Exception {                        // TODO Auto-generated method stub                        return addCache(key);                    }                });    }    private List<ObjectABC> addCache(String key) {    final JoiObjectMapper mapper = new JoiObjectMapper();        final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key), null, true);        final List<ObjectABC> configsList = new ArrayList<>();        allConfigFiles.forEach(configFile -> {            try {                     configsList.add(mapper.readValue(configFile, new TypeReference<ObjectABC>() {                      }));            } catch (Exception e) {                throw new RuntimeException(e);            }        });        return configsList;    }    public List<ObjectABC> getEntry(String key) {         try {            return cache.get(key);        } catch (ExecutionException e) {            throw new NonRetriableException(String.format(                    "Exception occured while trying to get data from cache for the key : {} Exception: {}",                    key.toString(), e));        }    }}在上面的代码中,当我传递 a String key(它是本地文件夹的路径)时,它会获取该位置存在的所有文件并将它们映射到ObjectABC使用ObjectMapper.现在我的问题是我想要一个通用的加载缓存,比如LoadingCache<String, List<Object>>.我想将不同文件夹中的文件映射到不同的对象,例如将/root/Desktop/folder1中的List<ObjectABC>文件映射到/root/Desktop/folder2 中的文件,List<ObjectDEF>并能够从缓存中存储和检索该信息。如何将用于映射的对象的信息传递给缓存?
查看完整描述

1 回答

?
米脂

TA贡献1836条经验 获得超3个赞

您可以创建一个自定义类,包装LoadingCache<Key<?>, Object>如下:


class HeterogeneousCache {


    private final LoadingCache<Key<?>, Object> cache;


    public <T> T get(Key<T> key) throws ExecutionException {

        return key.getType().cast(cache.get(key));

    }

}


@Value // provides constructor, getters, equals, hashCode

class Key<T> {


    private final String identifier;

    private final Class<T> type;

}

(为了简单起见,我使用了 Lombok 的@Value注释)


当然,这只是一个存根,您可能需要根据自己的需要进行调整。主要问题可能是您无法获得Class<List<ObjectABC>>- 您只能获得Class<List>. 最简单的方法是将 包装List<ObjectABC>在一些自定义类型中。更难的方法(不推荐)是使用 Guava 的TypeToken.


归因:此答案基于Frank Appel题为How to Map Distinct Value Types Using Java Generics的帖子,该帖子本身基于来自Effective Java 的Joshua Bloch的类型安全异构容器。


编辑:一个完整的解决方案

由于 OP 想要List<T>结果,并且因为他需要 的实例TypeReference<T>,我Class<T>用TypeReference<T>in替换Key<T>:


@Value // provides constructor, getters, equals, hashCode

class Key<T> {

    private final String identifier;

    private final TypeReference<T> typeReference;

}

这是CustomHeterogeneousCache现在的样子:


class CustomHeterogeneousCache {


    private final LoadingCache<Key<?>, List<?>> cache = CacheBuilder.newBuilder()

            .expireAfterAccess(10, TimeUnit.MINUTES)

            .maximumSize(25)

            .build(CacheLoader.from(this::computeEntry));


    @SuppressWarnings("unchecked")

    public <T> List<T> getEntry(Key<T> key) {

        return (List<T>) cache.getUnchecked(key);

    }


    private <T> List<T> computeEntry(Key<T> key) {

        final JoiObjectMapper mapper = new JoiObjectMapper();

        final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key.getIdentifier()), null, true);

        return allConfigFiles.stream()

                .map(configFile -> {

                    try {

                        return mapper.readValue(configFile, key.getTypeReference());

                    } catch (Exception e) {

                        throw new RuntimeException(e);

                    }

                })

                .collect(Collectors.toList());

    }

}

由于 的实现TypeReference没有值语义,用户必须确保每个都Key被创建一次,然后只被引用,例如:


class Keys {

    public static final Key<ObjectABC> ABC = new Key<>("/root/Desktop/folder1", new TypeReference<ObjectABC>() {

    });

    public static final Key<ObjectDEF> DEF = new Key<>("/root/Desktop/folder2", new TypeReference<ObjectDEF>() {

    });

}


查看完整回答
反对 回复 2022-01-06
  • 1 回答
  • 0 关注
  • 262 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信