@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
Как я могу указать @Cachable
использовать isbn
и checkWarehouse
как ключ?
Обновление : Текущая реализация кэша Spring использует все параметры метода в качестве ключа кэша если не указанный иначе. Если Вы хотите использовать выбранные ключи, обратитесь к ответ Arjan , который использует список SpEL {#isbn, #includeUsed}
, который является самым простым способом создать уникальные ключи.
стратегия генерации ключей по умолчанию, измененная с выпуском 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, из-за свойств такой функции возможна для этой задачи, но вычислить его каждый раз может быть слишком дорогим.
После некоторого ограниченного тестирования с 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;
}
}
Используйте это
@Cacheable(value="bookCache", key="#isbn + '_' + #checkWarehouse + '_' + #includeUsed")
Это будет работать
@Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")
Можно использовать выражение Spring-EL, для, например, на JDK 1.7:
@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")