Ключевые проблемы кэширования с Jcache

Я использую кэширование JSR107 с Springboot. У меня есть следующий метод.

@CacheResult(cacheName = "books.byidAndCat")
public List<Book> getAllBooks(@CacheKey final String bookId, @CacheKey final BookCategory bookCat) {

return <<Make API calls and get actual books>>
}

В первый раз он делает фактические вызовы API, а во второй раз без проблем загружает кеш. Я вижу следующую часть журнала.

Computed cache key SimpleKey [cb5bf774-24b4-41e5-b45c-2dd377493445,LT] for operation CacheResultOperation[CacheMethodDetails ...

Но проблема в том, что я хочу загрузить кеш, не делая даже первого вызова API, просто нужно заполнить кеш, как показано ниже.

String cacheKey  = SimpleKeyGenerator.generateKey(bookId, bookCategory).toString();     
        cacheManager.getCache("books.byidAndCat").put(cacheKey, deviceList);

Когда я проверяю, хэш-код ключей кеша в обоих случаях одинаков, но он выполняет вызовы API. Если хэш-код одинаков в обоих случаях, почему он выполняет вызовы API без учета кеша?

При отладке классов Spring было установлено, что org.springframework.cache.interceptor.SimpleKeyGenerator используется с генерацией ключа кэша, даже если @CacheResult присутствует. ИЗМЕНИТЬ и улучшить вопрос:

Кроме того, если у getAllBooks есть перегруженные методы, а затем вызвать этот кешированный метод через отдельный перегруженный метод, в этом случае также не работает кеширование методов.


person Ruchira Kariyawasam    schedule 24.05.2018    source источник


Ответы (2)


Я не эксперт по аннотациям JSR107 в контексте Spring. Вместо этого я использую аннотации Spring Cache.

При использовании JSR107 используется ключ GeneratedCacheKey. Так что это то, что вы должны поместить в свой кеш. Не toString() этого. Обратите внимание, что SimpleKeyGenerator не возвращает GeneratedCacheKey. Он возвращает SimpleKey, который является ключом, используемым Spring при использовании собственных аннотаций кэша вместо JSR-107. Для JSR-107 вам нужен файл SimpleGeneratedCacheKey.

Затем, если вы хотите предварительно загрузить кеш, просто вызовите getAllBooks перед тем, как он понадобится.

Если вы хотите предварительно загрузить кеш каким-либо другим способом, @javax.cache.annotation.CachePut должен помочь. См. его javadoc для примера.

person Henri    schedule 26.05.2018
comment
Я согласен, он должен быть сгенерирован CacheKey, и мы должны использовать генератор ключей с аннотацией cacheresult. Я голосую за ваш ответ. Но единственное, я хочу предварительно загрузить кеш без вызовов API. Если это вызовы API, то генерация ключей кеша происходит автоматически, и многого делать не нужно. - person Ruchira Kariyawasam; 26.05.2018
comment
Есть ли у нас правильный образец GeneratedCacheKey? Эта реализация (javatips.net/api/spring-framework-master/spring-context-support/) не ясен - person Ruchira Kariyawasam; 27.05.2018
comment
Если вы хотите установить кеш каким-либо другим способом, вам может понадобиться файл @CachePut. Я обновлю ответ соответственно. - person Henri; 28.05.2018
comment
Что касается ключа, вам нужен SimpleGeneratedCacheKey - person Henri; 28.05.2018
comment
этот кэшпут был бы хорошим подходом. Он должен обрабатывать параллелизм, и при обновлении все остальные результаты должны ждать завершения обновления. - person Ruchira Kariyawasam; 28.05.2018
comment
Я думаю, что мы можем использовать фиктивный метод cacheput, метод ничего не имеет, а просто использует только кэш. @ Анри, ты не видишь с этим проблем? , Если мы используем аннотацию синхронизации, это означает, что все запросы будут ждать завершения кэширования. - person Ruchira Kariyawasam; 28.05.2018

Как предложил @Henri, мы можем использовать cacheput. Но для этого нам нужны методы. Ниже мы можем обновить кеш, очень похожий на cacheput,

//перегруженный метод доступен как с id, так и с cat.

List<Object> bookIdCatCache = new ArrayList<>();
    bookIdCatCache.add(bookId);
    bookIdCatCache.add(deviceCat);
    Object bookIdCatCacheKey  = SimpleKeyGenerator.generateKey(bookIdCatCache.toArray(new Object[bookIdCatCache.size()]));
    cacheManager.getCache("books.byidAndCat").put(bookIdCatCacheKey , bookListWithIdAndCat);

//перегружен только id метода

List<Object> bookIdCache = new ArrayList<>();
        String nullKey          = null
        bookIdCache.add(bookId);
        bookIdCache.add(nullKey);
        Object bookIdCacheKey  = SimpleKeyGenerator.generateKey(bookIdCache.toArray(new Object[bookIdCache.size()]));
        cacheManager.getCache("books.byidAndCat").put(bookIdCacheKey , bookListWithId);

//Неверно (моя предыдущая реализация)

String cacheKey  = SimpleKeyGenerator.generateKey(bookId, bookCategory).toString();

//Правильно (это из весны)

Object cacheKey  = SimpleKeyGenerator.generateKey(bookIdCatCache.toArray(new Object[bookIdCatCache.size()]));
person Ruchira Kariyawasam    schedule 28.05.2018
comment
Поскольку других лучших ответов нет, выбрал этот в качестве ответа. - person Ruchira Kariyawasam; 29.05.2018