30 июля 2022
Тэги: gradle, Java, maven, Spring, Spring Boot.
Spring Boot поддерживает простой механизм кеширования данных. Рассмотрим его на примере, исходники которого доступны на github.
Создадим стандартное приложение Spring Boot. Это удобно делать через Spring Initializr. Если вы используете gradle, то в файле build.gradle должны быть две зависимости:
Если же вы используете maven, то зависимости будут в файле pom.xml:
Зависимость spring-boot-starter-web – это базовая функциональность нашего веб-приложения, в том числе поддержка rest-контроллеров. Зависимость spring-boot-starter-cache добавляет возможность кеширования.
Предположим, что мы хотим кешировать некие записи, представленные классом MyRecord. Очевидно, что в последних версиях Java это должен быть не просто класс, а record-класс. То есть класс, предназначенный для хранения данных. Все поля доступа и служебные методы для него компилятор генерирует автоматически.
MyRecord содержит всего лишь два поля: числовой идентификатор и время создания для наглядной демонстрации изменения состояния кеша.
Предположим, что извлечение этих данных без кеширования является дорогой по времени операцией. Для этого создадим сервис, который будет имитировать «тяжёлое» обращение к хранилищу с данными, которое мы хотим закешировать.
В реальных проектах обращение к БД, либо к удалённому сервису может быть очень долгим, поэтому имеет смысл кешировать редко изменяющиеся объекты.
Далее добавляем в сервис три метода: getOrCreateRecord(), createOrUpdateRecord() и deleteRecord().
Метод getOrCreateRecord() возвращает объект по его id. Имитация «тяжёлого» обращения к БД делается с помощью метода TimeUnit.SECONDS.sleep(3), который приостанавливает выполнение потока на 3 секунды. Затем просто создаём новый объект и возвращаем его как результат. Аннотация @Cacheable говорит, что возвращаемый результат необходимо положить в кеш, если его там нет. А если он там есть, то просто вернуть значение из кеша. Параметр cacheNames указывает на имя кеша, а key указывает параметр метода, по значению которого проверять наличие элемента в кеше. Обратите внимание на символ «#», стоящий перед именем параметра.
Таким образом при первом обращении к методу вы заметите задержку в 3 секунды, а затем получите в ответ созданный объект. При последующих обращениях с тем же id результат будет возвращаться мгновенно, т.к. значения будут браться из кеша и дата создания объекта меняться не будет.
Метод createOrUpdateRecord() создаёт новый объект MyRecord и возвращает его в качестве результата. Аннотация @CachePut принудительно помещает объект, возвращаемый данным методом, в кеш. Если в кеше по данному ключу уже был объект, он будет перезаписан. Имя кеша, аналогично предыдущей аннотации, указывается в параметре cacheNames, а имя параметра метода, по значению которого следует искать запись в кеше – через параметр key.
Таким образом, каждый раз после выполнения этого метода в кеше будут обновляться записи.
Наконец, метод deleteRecord() сам ничего не делает. Однако аннотация @CacheEvict удаляет запись из кеша по указанному ключу recordId. Таким образом, после выполнения данного метода в кеше будет удаляться одна запись.
Теперь создадим простой RestController, чтобы можно было вызывать наши методы по http.
При запуске приложения данный контроллер по умолчанию будет доступен по адресу 127.0.0.1:8080. Метод getOrCreateRecord вызывается с помощью GET-запроса по адресу 127.0.0.1:8080/{id}, где id – номер нашей записи. Аналогично метод createOrUpdateRecord вызывается PUT-запросом по тому же адресу с указанием id записи. А метод deleteRecord – DELETE-запросом.
Для активации механизма кеширования не забудьте добавить аннотацию @EnableCaching в основной класс нашего приложения, туда, где находится стандартный метод main() и аннотация @SpringBootApplication.
Запускаем приложение и делаем GET-запрос на 127.0.0.1:8080/1. Мы наблюдаем долгий ответ, т.е. для id = 1 объекта в кеше ещё нет. Повторные запросы выполняются мгновенно, а ответ возвращается один и тот же. Далее делаем PUT-запрос на тот же адрес. Объект будет создан и принудительно помещён в кеш. Ещё раз выполняем тот же GET-запрос и наблюдаем быстрый ответ, который вернёт нам сущность, созданную методом PUT. Теперь удалим эту запись, выполнив DELETE-запрос. И затем ещё раз GET-запрос – он опять ответит с задержкой. То есть после DELETE записи в кеше не было.
Метод с аннотацией @Cacheable* не выполняется, если по указанному id в кеше уже есть запись. Она будет извлечена из кеша и возвращена в качестве результата работы метода.
Метод с аннотацией @CachePut* можно вызывать любое количество раз для одного и того же id. И каждый раз объект в кеше будет обновляться. При этом важно, чтобы метод, помеченный этой аннотацией, возвращал обновлённый объект.
Kotlin, Java, Java 11, Java 8, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.
16.04.2022 09:30 Михаил
Спасибо!)