@Cacheable
в Spring 3.1, которая используется для маркировки методов, возвращаемые значения которых будут храниться в кэше. Тем не менее, @Cacheable
— это только одна из пары аннотаций, которые разработчики Spring разработали для кэширования, а другая — @CacheEvict
.
Как и @Cacheable
, @CacheEvict
имеет @CacheEvict
value
, key
и condition
. Они работают точно так же, как и те, которые поддерживаются @Cacheable
, поэтому дополнительную информацию о них смотрите в моем предыдущем блоге: Spring 3.1 Caching и @Cacheable .
CacheEvict
поддерживает два дополнительных атрибута: allEntries
и beforeInvocation
. Если бы я был азартным человеком, я бы положил деньги на самый популярный из них — allEntries
. allEntries
используется для полной очистки содержимого кэша, определенного @CacheEvict
обязательного value
@CacheEvict
. Метод ниже демонстрирует, как применить allEntries
:
1
2
3
4
|
@CacheEvict (value = "employee" , allEntries = true ) public void resetAllEntries() { // Intentionally blank } |
resetAllEntries()
устанавливает для @CacheEvict
allEntries
значение «true» и, предполагая, что метод findEmployee(...)
выглядит следующим образом:
1
2
3
4
5
|
@Cacheable (value = "employee" ) public Person findEmployee(String firstName, String surname, int age) { return new Person(firstName, surname, age); } |
… Затем в следующем коде resetAllEntries()
очистит кэш «сотрудников». Это означает, что в приведенном ниже тесте JUnit employee1
не будет ссылаться на тот же объект, что и employee2
:
1
2
3
4
5
6
7
8
9
|
@Test public void testCacheResetOfAllEntries() { Person employee1 = instance.findEmployee( "John" , "Smith" , 22 ); instance.resetAllEntries(); Person employee2 = instance.findEmployee( "John" , "Smith" , 22 ); assertNotSame(employee1, employee2); } |
Второй атрибут — beforeInvocation
. Это определяет, удаляются ли элемент (ы) данных из кэша до или после вызова вашего метода.
Код ниже довольно бессмысленный; тем не менее, он демонстрирует, что вы можете одновременно применять @CacheEvict
и @Cacheable
к методу.
1
2
3
4
5
6
|
@CacheEvict (value = "employee" , beforeInvocation = true ) @Cacheable (value = "employee" ) public Person evictAndFindEmployee(String firstName, String surname, int age) { return new Person(firstName, surname, age); } |
В приведенном выше коде @CacheEvict
удаляет все записи в кэше с соответствующим ключом, прежде чем @Cacheable
поиск в кэше. Поскольку @Cacheable
не найдет никаких записей, он вызовет мой код, хранящий результат в кэше. Последующий вызов моего метода вызовет @CacheEvict
который удалит все соответствующие записи, в результате чего в тесте JUnit ниже переменной employee1
никогда не будет ссылаться на тот же объект, что и employee2
:
1
2
3
4
5
6
7
8
|
@Test public void testBeforeInvocation() { Person employee1 = instance.evictAndFindEmployee( "John" , "Smith" , 22 ); Person employee2 = instance.evictAndFindEmployee( "John" , "Smith" , 22 ); assertNotSame(employee1, employee2); } |
Как я уже говорил выше, evictAndFindEmployee(...)
кажется несколько бессмысленным, поскольку я применяю и @Cacheable
и @CacheEvict
к @Cacheable
и @CacheEvict
же методу. Но более того, это делает код неясным и нарушает принцип единой ответственности; следовательно, я бы рекомендовал создать отдельные методы кеширования и кеширования. Например, если у вас есть метод кэширования, такой как:
1
2
3
4
5
|
@Cacheable (value = "employee" , key = "#surname" ) public Person findEmployeeBySurname(String firstName, String surname, int age) { return new Person(firstName, surname, age); } |
затем, предполагая, что вам нужно более точное управление кэшем, чем простое «прозрачное все», вы можете легко определить его аналог:
1
2
3
4
5
|
@CacheEvict (value = "employee" , key = "#surname" ) public void resetOnSurname(String surname) { // Intentionally blank } |
Это простой пустой маркерный метод, который использует то же выражение SpEL, которое применялось к @Cacheable
чтобы @Cacheable
все экземпляры Person
из кэша, где ключ соответствует аргументу ‘фамилия’.
1
2
3
4
5
6
7
8
|
@Test public void testCacheResetOnSurname() { Person employee1 = instance.findEmployeeBySurname( "John" , "Smith" , 22 ); instance.resetOnSurname( "Smith" ); Person employee2 = instance.findEmployeeBySurname( "John" , "Smith" , 22 ); assertNotSame(employee1, employee2); } |
В приведенном выше коде первый вызов findEmployeeBySurname(...)
создает объект Person
, который Spring сохраняет в кэше «employee» с ключом, определенным как «Smith». Вызов resetOnSurname(...)
очищает все записи из кэша «employee» с фамилией «Smith», и, наконец, второй вызов findEmployeeBySurname(...)
создает новый объект Person
, который Spring снова сохраняет в « сотрудник »кеш с ключом« кузнец ». Следовательно, переменные employee1
и employee2
не ссылаются на один и тот же объект.
Изучив аннотации кэширования Spring, следующая часть головоломки заключается в том, чтобы разобраться с настройкой практического кэширования: как включить кэширование Spring и какую реализацию кэширования следует использовать? Подробнее об этом позже …
Приятного кодирования и не забудьте поделиться!
Ссылка: Spring 3.1 Caching и @CacheEvict от нашего партнера по JCG Роджера Хьюза в блоге Captain Debug’s Blog .