@Cacheable включают несколько аргументов метода

Из пружинной документации:

@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

Как я могу указать @Cachable использовать isbn и checkWarehouse как ключ?

62
задан 28 December 2012 в 20:14

5 ответов

Обновление : Текущая реализация кэша Spring использует все параметры метода в качестве ключа кэша если не указанный иначе. Если Вы хотите использовать выбранные ключи, обратитесь к ответ Arjan , который использует список SpEL {#isbn, #includeUsed}, который является самым простым способом создать уникальные ключи.

От Spring Documentation

стратегия генерации ключей по умолчанию, измененная с выпуском Spring 4.0. Более ранние версии Spring использовали стратегию генерации ключей, которая, для нескольких основных параметров, только рассмотрела хэш-код () параметров и не равняется (); это могло вызвать неожиданные ключевые коллизии (см. SPR-10237 для фона). Новый 'SimpleKeyGenerator' использует первичный ключ для таких сценариев.

Перед Spring 4.0

я предлагаю Вас concat значения параметров в выражении Spel с чем-то как key="#checkWarehouse.toString() + #isbn.toString()"), я полагаю, что это должно работать org.springframework.cache.interceptor. ExpressionEvaluator возвращает Объект, который позже используется в качестве ключа, таким образом, Вы не должны обеспечивать int в Вашем выражении SPEL.

Что касается хэш-кода с высокой вероятностью коллизии - Вы не можете использование это как ключ.

Кто-то в этом потоке предложил использовать T(java.util.Objects).hash(#p0,#p1, #p2), но он НЕ будет РАБОТАТЬ, и этот подход легко повредить, например, я использовал данные от SPR-9377:

    System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
    System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));

Обе строки печатают-636517714 на моей среде.

P.S. На самом деле в справочной документации мы имеем

@Cacheable(value="books", key="T(someType).hash(#isbn)") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

, я думаю, что этот пример является НЕПРАВИЛЬНЫМ и вводящим в заблуждение и должен быть удален из документации, поскольку ключи должны быть уникальными.

P.P.S. также видят https://jira.springsource.org/browse/SPR-9036 для некоторых интересных идей относительно генерации ключей по умолчанию.

я хотел бы добавить ради правильности и как интересное то, что с помощью безопасного криптографическая хеш-функция как SHA256, из-за свойств такой функции возможна для этой задачи, но вычислить его каждый раз может быть слишком дорогим.

77
ответ дан 31 October 2019 в 13:36

После некоторого ограниченного тестирования с Spring 3.2, кажется, что можно использовать список SpEL: {..., ..., ...}. Это может также включать null значения. Spring передает список как ключ к фактической реализации кэша. Когда использование Ehcache, такой в какой-то момент вызовет List#hashCode () , который принимает все его объекты во внимание. (Я не уверен, полагаются ли Ehcache только на хэш-код.)

я использую это для общего кэша, в котором я включаю имя метода в ключ также, который значение по умолчанию Spring ключевой генератор не включает . Таким образом, я могу легко вытереть (единственный) кэш, без (слишком много...) рискующий соответствием ключам для различных методов. Как:

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #isbn?.id, #checkWarehouse }")
public Book findBook(ISBN isbn, boolean checkWarehouse) 
...

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #asin, #checkWarehouse }")
public Book findBookByAmazonId(String asin, boolean checkWarehouse)
...

, Конечно, если для многих методов нужно это и Вы всегда используете все параметры для своего ключа, затем можно также определить пользовательский ключевой генератор, который включает имя класса и имя метода:

<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />

... с:

public class CacheKeyGenerator 
  implements org.springframework.cache.interceptor.KeyGenerator {

    @Override
    public Object generate(final Object target, final Method method, 
      final Object... params) {

        final List<Object> key = new ArrayList<>();
        key.add(method.getDeclaringClass().getName());
        key.add(method.getName());

        for (final Object o : params) {
            key.add(o);
        }
        return key;
    }
}
63
ответ дан 31 October 2019 в 13:36

Используйте это

@Cacheable(value="bookCache", key="#isbn + '_' + #checkWarehouse + '_' + #includeUsed")
-2
ответ дан 31 October 2019 в 13:36

Это будет работать

@Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")
0
ответ дан 31 October 2019 в 13:36

Можно использовать выражение Spring-EL, для, например, на JDK 1.7:

@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")
4
ответ дан 31 October 2019 в 13:36

Другие вопросы по тегам:

Похожие вопросы: