Spring cache/jsr107: аргумент list/collection как часть ключа
У меня есть служба, которая вызывает внешнюю систему, чтобы получить какие-то объекты по их внешнему идентификатору, а также отправить их обратно для обновления. Вместо того, чтобы извлекать объекты один за другим, есть более общие целевые методы:
public interface ExternalSystem {
List<ExternalDTO> getObjects(List<String> externalIds);
void updateObjects(List<ExternalDTO> updates);
}
Я хотел бы поместить кэш поверх вызовов ExternalSystem, потому что они довольно дорогие.
При реализации сервиса я могу просто поставить весенние аннотации:
@Cacheable("cache-external")
List<ExternalDTO> getObjects(List<String> externalIds) {}
@CacheEvict(cacheNames="cache-external", allEntries=true)
void updateObjects(List<ExternalDTO> updates);
Тем не менее, такой кеш будет работать очень плохо, если у меня много пересечений между externalIds, т.е.
- Вызовите getObjects #1 ([1,2,3,4]) -> кеш, помещенный ключом [1,2,3,4]
- Вызов #2 getObjects([1,2,3,4,5]) -> кеш, помещенный ключом [1,2,3,4,5]
- Вызовите 3 getObjects([6,7,8,9]) -> кеш, помещенный ключом [6,7,8,9]
- Вызвать # 4 updateObjects ( 1) -> удалить все кэши, но третий кэш не содержит 3
Итак, вопрос заключается в том, как реализовать собственную стратегию (я полагаю, что она не выполнима из коробки), которая будет исключать только те записи, которые действительно должны быть удалены, и сделает ключи таким образом, чтобы пересекающиеся объекты извлекались из кэша.?
Upd. Я нашел два похожих вопроса:
- пружинно-кэш-абстракция-с многозначными-запросами
- используя пружинный-кэш-на-методы, которые забирают ан-массив или сбор
- весна-кэшируемая-метода-с-списки
UPD2. Вот что-то похожее на то, что я хочу, за исключением того, что я помещу в кеш пары String и ExternalDTO для каждого элемента в коллекции. элемент уровня кэширования, из-списка к списку
1 ответ
AFAIK это невозможно с аннотациями. Вы можете использовать императивный API, который содержит необходимые вам массовые операции, например Cache.getAll(keySet)
а также Cache.removeAll(keySet)
Для меня с этой конфигурацией все работало нормально. Это обфусцированная версия моего кода.
@Cacheable(cacheNames = "test", key = "#p0")
public List<String> getTestFunction(List<String> someIds) {
getTestFunction(Arrays.asList("A","B","C"));
2020-04-02 15:12:35.492 TRACE 18040 --- [Test worker] o.s.cache.interceptor.CacheInterceptor : Computed cache key '[A, B, C]' for operation Builder[public java.util.List org.Main.getTestFunction(java.util.List)] caches=[test] | key='#p0' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
Вы видите, что это конкатенированные строки
... Computed cache key '[A, B, C]' ...
Моя настройка:/resources/ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<cache name="test"
maxBytesLocalHeap="1M"
timeToLiveSeconds="300"/>
</ehcache>
gradle.build
plugins {
id "org.springframework.boot" version "2.2.4.RELEASE"
....
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter-cache"
implementation "org.ehcache:ehcache:3.8.1"
...
}