使用番石榴缓存减少样板的方法

时间:2013-10-31 16:36:34

标签: java caching guava

我有很多像PersonDao这样的数据访问对象,其方法如下:

Person findById(String id) {}
List<Person> search(String firstName, LastName, Page) {}
int searchCount(String firstName, LastName) {}

我已经通过在其中一个类中添加番石榴缓存进行了实验,这非常好,但是有很多样板。

这是一个让findById先在缓存中查看的例子:

private final LoadingCache<String, Person> cacheById = CacheBuilder.newBuilder()
  .maximumSize(maxItemsInCache)
  .expireAfterWrite(cacheExpireAfterMinutes, TimeUnit.MINUTES)
  .build(new CacheLoader<String, Person>() {
    public Person load(String key) {
      return findByIdNoCache(key);
  });
//.... and update findById to call the cache ...
@Override
public Person findById(String id) {
  return cacheById.getUnchecked(id);
}

因此,因为每个方法都有不同的参数和返回类型,所以我最终为每个方法创建了一个单独的cacheLoader!

我尝试将所有内容整合到一个CacheLoader中,该CacheLoader返回Object类型并接受一个对象Map,但后来我最终得到了丑陋的if / else来确定要调用哪个方法来加载缓存。

我正在努力寻找一种优雅的方法来为这些数据访问对象添加缓存,任何建议?也许guava缓存不适用于这个用例?

2 个答案:

答案 0 :(得分:5)

试试这个。不幸的是,由于泛型而存在编译器警告......但我们可能会压制它们,因为我们知道不会发生任何不良事件。

public class CacheContainer {

    private static final long maxItemsInCache = 42;
    private static final long cacheExpireAfterMinutes = 42;
    private final Map<String, LoadingCache> caches = Maps.newHashMap();


    public <K, V> V getFromCache(String cacheId, K key, CacheLoader<K, V> loader) throws ExecutionException {
        LoadingCache<K, V> cache = caches.get(cacheId);
        if (cache == null) {
            cache = CacheBuilder.newBuilder().
                     maximumSize(maxItemsInCache).
                     expireAfterWrite(cacheExpireAfterMinutes, TimeUnit.MINUTES).
                     build(loader);
            caches.put(cacheId, cache);
        }
        return cache.get(key);
    }
}

然后在你的道:

private final CacheContainer cacheContainer = new CacheContainer();


public Person findById(String id) {
    cacheContainer.getFromCache("personById", id, new CacheLoader<String, Person>() {
        @Override
        public Person load(String key) {
          return findByIdNoCache(key);
      });
}

其他方法也是一样的。我不认为你可以减少样板。

答案 1 :(得分:1)

为每个要缓存结果的方法创建CacheLoader(和单独的缓存)是必要的。您可以通过创建一个具有所需缓存配置的CacheBuilder来简化一些事情,然后创建每个缓存:

private final CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder()
    .maximumSize(maxItemsInCache)
    .expireAfterWrite(cacheExpireAfterMinutes, TimeUnit.MINUTES);

private final LoadingCache<String, Person> cacheById = builder.build(
    new CacheLoader<String, Person>() {
      // ...
    });

 private final LoadingCache<Search, List<Person>> searchCache = builder.build(
     new CacheLoader<Search, List<Person>>() {
       // ...
     });

  // etc.