@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
|
@Testpublic 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
|
@Testpublic 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
|
@Testpublic 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 .