Перейти к основному содержимому

Пример Spring Boot Ehcache

· 4 мин. чтения

1. Обзор

Давайте рассмотрим пример использования Ehcache с Spring Boot. Мы будем использовать Ehcache версии 3, так как она обеспечивает реализацию менеджера кэша JSR-107 .

Примером является простая служба REST, которая производит квадрат числа.

2. Зависимости

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.6.1</version></dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>

3. Пример

Давайте создадим простой контроллер REST, который вызывает службу для возведения числа в квадрат и возвращает результат в виде строки JSON:

@RestController
@RequestMapping("/number", MediaType.APPLICATION_JSON_UTF8_VALUE)
public class NumberController {

// ...

@Autowired
private NumberService numberService;

@GetMapping(path = "/square/{number}")
public String getSquare(@PathVariable Long number) {
log.info("call numberService to square {}", number);
return String.format("{\"square\": %s}", numberService.square(number));
}
}

Теперь давайте создадим сервис.

Мы аннотируем метод @Cacheable , чтобы Spring обрабатывал кэширование. В результате этой аннотации Spring создаст прокси NumberService для перехвата вызовов квадратного метода и вызова Ehcache.

Нам нужно указать имя используемого кеша и, возможно, ключ. Мы также можем добавить условие для ограничения того, что кешируется:

@Service
public class NumberService {

// ...
@Cacheable(
value = "squareCache",
key = "#number",
condition = "#number>10")
public BigDecimal square(Long number) {
BigDecimal square = BigDecimal.valueOf(number)
.multiply(BigDecimal.valueOf(number));
log.info("square of {} is {}", number, square);
return square;
}
}

Наконец, давайте создадим наше основное приложение Spring Boot:

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

4. Конфигурация кэша

Нам нужно добавить аннотацию Spring @EnableCaching к bean-компоненту Spring, чтобы включить управление кэшем Spring на основе аннотаций.

Давайте создадим класс CacheConfig :

@Configuration
@EnableCaching
public class CacheConfig {
}

Автоконфигурация Spring находит реализацию Ehcache JSR-107. Однако по умолчанию кэши не создаются.

Потому что ни Spring, ни Ehcache не ищут файл ehcache.xml по умолчанию . Мы добавляем следующее свойство, чтобы сообщить Spring, где его найти:

spring.cache.jcache.config=classpath:ehcache.xml

Давайте создадим файл ehcache.xml с кешем, который называется SquareCache :

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

<cache alias="squareCache">
<key-type>java.lang.Long</key-type>
<value-type>java.math.BigDecimal</value-type>
<expiry>
<ttl unit="seconds">30</ttl>
</expiry>

<listeners>
<listener>
<class>com.foreach.cachetest.config.CacheEventLogger</class>
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<event-ordering-mode>UNORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
</listener>
</listeners>

<resources>
<heap unit="entries">2</heap>
<offheap unit="MB">10</offheap>
</resources>
</cache>

</config>

И давайте также добавим прослушиватель событий кеша, который регистрирует как CREATED , так и EXPIRED события кеша:

public class CacheEventLogger 
implements CacheEventListener<Object, Object> {

// ...

@Override
public void onEvent(
CacheEvent<? extends Object, ? extends Object> cacheEvent) {
log.info(/* message */,
cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
}
}

5. В действии

Мы можем использовать Maven для запуска этого приложения, запустив mvn spring-boot:run .

Затем откройте браузер и получите доступ к службе REST через порт 8080.

Если мы перейдем на http://localhost:8080/number/square/12 , то получим обратно {“square”:144} , а в логе увидим:

INFO [nio-8080-exec-1] c.b.cachetest.rest.NumberController : call numberService to square 12
INFO [nio-8080-exec-1] c.b.cachetest.service.NumberService : square of 12 is 144
INFO [e [_default_]-0] c.b.cachetest.config.CacheEventLogger : Cache event CREATED for item with key 12. Old value = null, New value = 144

Мы можем увидеть сообщение журнала из квадратного метода NumberService и событие CREATED из EventLogger. Если мы затем обновим браузер, мы увидим только следующее, добавленное в журнал:

INFO [nio-8080-exec-2] c.b.cachetest.rest.NumberController : call numberService to square 12

Сообщение журнала в квадратном методе NumberService не вызывается. Это показывает нам, что кэшированное значение используется.

Если мы подождем 30 секунд до истечения срока действия кэшированного элемента и обновим браузер, мы увидим событие EXPIRED , а значение будет добавлено обратно в кеш:

INFO [nio-8080-exec-1] (...) NumberController : call numberService to square 12
INFO [e [_default_]-1] (...) CacheEventLogger : Cache event EXPIRED for item with key 12. Old value = 144,New value = null
INFO [nio-8080-exec-1] (... )NumberService : square of 12 is 144
INFO [e [_default_]-1] (...) CacheEventLogger : Cache event CREATED for item with key 12. Old value = null, New value = 144

Если мы введем http://localhost:8080/number/square/3 в браузере, мы получим правильный ответ 9, но значение не кэшируется.

Это связано с условием, которое мы использовали в аннотации @Cacheable , чтобы кэшировать только значения для чисел выше 10.

6. Заключение

В этом кратком руководстве мы показали, как настроить Ehcache с помощью Spring Boot.

Как всегда, код можно найти на GitHub .