Если вариант с аннотациями не подходят (возможно, ввиду отсутствия доступа к источникам или внешнего кода), можно использовать XML для декларативного кэширования. Таким образом, вместо аннотирования методов для кэширования можно задать целевой метод и директивы кэширования извне (аналогично Advice для управления декларативными транзакциями). Пример из предыдущего раздела можно переложить на следующий пример:
<!-- служба, которую нам нужно сделать кэшируемой -->
<bean id="bookService" class="x.y.service.DefaultBookService"/>
<!-- определения кэша -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
<cache:caching cache="books">
<cache:cacheable method="findBook" key="#isbn"/>
<cache:cache-evict method="loadBooks" all-entries="true"/>
</cache:caching>
</cache:advice>
<!-- применяем кэшируемую логику работы ко всем интерфейсам BookService -->
<aop:config>
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.BookService.*(..))"/>
</aop:config>
<!-- определение диспетчера кэша опущено -->
В предыдущей конфигурации служба bookService
сделана кэшируемой. Применяемая семантика кэширования инкапсулирована в определении cache:advice
, что позволяет использовать метод findBooks
для помещения данных в кэш, а метод loadBooks
– для вытеснения данных. Оба определения работают относительно кэша books
.
Определение aop:config
применяет Advice кэша к соответствующим точкам программы с помощью выражения среза на AspectJ. В предыдущем примере описаны все методы из BookService
, и к ним можно применять Advice кэша.
Декларативное кэширование XML поддерживает любые модели, основанные на аннотациях, поэтому переход между ними должен быть довольно простым. Более того, оба подхода могут использоваться в одном приложении. Подход на основе XML не затрагивает целевой код. Однако по своей природе он более перегружен. При работе с классами, имеющими перегруженные методы, которые предназначены для кэширования, определение нужных методов требует дополнительных усилий, поскольку аргумент для method
не является хорошим дискриминатором. В этих случаях можно использовать срез из AspectJ, чтобы выбрать целевые методы и применять соответствующую функциональность кэширования. Однако через XML легче применять кэширование в масштабах пакета, группы или интерфейса (опять же, благодаря срезу из AspectJ) и создавать шаблоноподобные определения (как это сделано в предыдущем примере путём определения целевого кэша с помощью атрибута cache:definitions cache
).