具有项目/实体集合的弹簧缓存

2022-09-01 05:26:30

我正在使用Spring Cache,在那里我传入了一个密钥集合,返回的是实体列表。我希望缓存框架了解返回列表中的每个元素都将使用相应的代码进行缓存。目前,密钥似乎是整个列表,如果我在后续调用中缺少密钥,它将尝试再次重新加载整个集合。

@Override
@Cacheable(value = "countries")
public List<Country> getAll(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

另一种可能性是返回是一个映射,同样,我希望缓存足够智能,只能查询以前从未查询过的项目,也可以使用其键缓存每个项目。

@Override
@Cacheable(value = "countries")
public Map<String,Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

假设国家/地区类如下所示:

class Country{
  String code; 
  String fullName;
  long id;

... // getters setters constructurs etc.. 
}

使用Spring Cache可以做到这一点吗?


答案 1

事实上,即使使用Spring的缓存抽象,这也是可能的,但不是开箱即用的(OOTB)。从本质上讲,您必须自定义Spring的缓存基础架构(下面将进一步解释)

默认情况下Spring 的缓存基础结构使用整个方法参数参数作为缓存“键”,如此所述。当然,您也可以使用 SpEL 表达式或自定义实现来自定义密钥分辨率,如此所述。@CacheableKeyGenerator

尽管如此,这不会参数参数的集合或数组以及方法的返回值分解为单独的缓存条目(即基于数组/集合或Map.key/值对)。@Cacheable

为此,您需要Spring的自定义实现(取决于您的缓存策略/提供程序)和接口。CacheManagerCache

注意:具有讽刺意味的是,这将是我第三次回答几乎相同的问题,首先在这里,然后在这里,现在在这里,:-)。无论如何。。。

我已经更新/清理了我的示例(一点)为这篇文章。

请注意,我的示例扩展并自定义Spring框架本身中提供的ConcurrentMapCacheManager

从理论上讲,您可以扩展/自定义任何实现,例如Spring Data Redis中的Redis这里来源),或Spring Data GemFire中的Pivotal GemFire这里来源)。Pivotal GemFire的开源版本是Apache Geode,它有一个相应的Spring Data Geode项目(Spring Data Geode中的CacheManager来源,与SD GemFire基本相同)。当然,您可以将此技术应用于其他缓存提供程序...Hazelcast,Ehcache等CacheManagerCacheManager

但是,工作的真正内脏是由SpringCache接口的自定义实现(或者更具体地说,基类)处理的。

无论如何,希望从我的例子中,您将能够弄清楚您需要在应用程序中执行哪些操作以满足应用程序的缓存要求。

此外,您可以应用相同的方法来处理 ,但我会将其作为练习留给您,;-)。Maps

希望这有帮助!

干杯,约翰


答案 2

使用 和 帮助器方法,您可以像这样非常简单地实现它:@CachePut

public List<Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

public void preloadCache(List<String>codes) {
    List<Country> allCountries = getAllByCode(codes);
    for (Country country : allCountries) {
        cacheCountry(country);
    }
}

@CachePut
public Country cacheCountry(Country country) {
    return country;
}

注意

这只会向缓存中添加值,但绝不会删除旧值。您可以在添加新值之前轻松执行缓存逐出

备选案文2

有一个建议可以让它像这样工作:

@CollectionCacheable
public List<Country> getAllByCode(List<String>codes) {    

看:

如果您不耐烦,请从GitHub获取代码并在本地集成


推荐