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

Использование нескольких менеджеров кеша в Spring

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

1. Обзор

В этом руководстве мы узнаем, как настроить несколько менеджеров кеша в приложении Spring.

2. Кэширование

Spring применяет кэширование к методам, чтобы наше приложение не выполняло один и тот же метод несколько раз для одного и того же ввода.

Реализовать кэширование в приложении Spring очень просто . Это можно сделать, добавив аннотацию @EnableCaching в наш класс конфигурации:

@Configuration
@EnableCaching
public class MultipleCacheManagerConfig {}

Затем мы можем начать кэшировать вывод метода, добавив аннотацию @Cacheable к методу:

@Cacheable(cacheNames = "customers")
public Customer getCustomerDetail(Integer customerId) {
return customerDetailRepository.getCustomerDetail(customerId);
}

Как только мы добавим указанную выше конфигурацию, Spring Boot сам создаст для нас менеджер кеша.

По умолчанию он использует ConcurrentHashMap в качестве базового кеша, если мы явно не указали какой-либо другой .

3. Настройка нескольких менеджеров кэша

В некоторых случаях нам может понадобиться использовать более одного менеджера кеша в нашем приложении. Итак, давайте посмотрим, как мы можем сделать это в нашем приложении Spring Boot на примере.

В нашем примере мы будем использовать CaffeineCacheManager и простой ConcurrentMapCacheManager .

CaffeineCacheManager предоставляется стартером spring-boot-starter-cache . Он будет автоматически настроен Spring, если присутствует Caffeine , который представляет собой библиотеку кэширования, написанную на Java 8.

ConcurrentMapCacheManager использует реализацию кеша с использованием C oncurrentHashMap .

Мы можем сделать это следующими способами.

3.1. Использование @Primary

Мы можем создать два bean-компонента менеджеров кеша в нашем классе конфигурации. Затем мы можем сделать один компонент основным:

@Configuration
@EnableCaching
public class MultipleCacheManagerConfig {

@Bean
@Primary
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("customers", "orders");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.maximumSize(500)
.weakKeys()
.recordStats());
return cacheManager;
}

@Bean
public CacheManager alternateCacheManager() {
return new ConcurrentMapCacheManager("customerOrders", "orderprice");
}
}

Теперь Spring Boot будет использовать CaffeineCacheManager по умолчанию для всех методов, пока мы явно не укажем наш alterCacheManager для метода:

@Cacheable(cacheNames = "customers")
public Customer getCustomerDetail(Integer customerId) {
return customerDetailRepository.getCustomerDetail(customerId);
}

@Cacheable(cacheNames = "customerOrders", cacheManager = "alternateCacheManager")
public List<Order> getCustomerOrders(Integer customerId) {
return customerDetailRepository.getCustomerOrders(customerId);
}

В приведенном выше примере наше приложение будет использовать CaffeineCacheManager для метода getCustomerDetail() . А для метода getCustomerOrders() он будет использовать alterCacheManager .

3.2. Расширение CachingConfigurerSupport

Другой способ сделать это — расширить класс CachingConfigurerSupport и переопределить метод cacheManager (). Этот метод возвращает bean-компонент, который будет менеджером кеша по умолчанию для нашего приложения:

@Configuration
@EnableCaching
public class MultipleCacheManagerConfig extends CachingConfigurerSupport {

@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("customers", "orders");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.maximumSize(500)
.weakKeys()
.recordStats());
return cacheManager;
}

@Bean
public CacheManager alternateCacheManager() {
return new ConcurrentMapCacheManager("customerOrders", "orderprice");
}
}

Обратите внимание, что мы все еще можем создать еще один компонент с именем alterCacheManager. Мы можем использовать этот alterCacheManager для метода, явно указав его, как в последнем примере.

3.3. Использование CacheResolver

Мы можем реализовать интерфейс CacheResolver и создать собственный CacheResolver :

public class MultipleCacheResolver implements CacheResolver {

private final CacheManager simpleCacheManager;
private final CacheManager caffeineCacheManager;
private static final String ORDER_CACHE = "orders";
private static final String ORDER_PRICE_CACHE = "orderprice";

public MultipleCacheResolver(CacheManager simpleCacheManager,CacheManager caffeineCacheManager) {
this.simpleCacheManager = simpleCacheManager;
this.caffeineCacheManager=caffeineCacheManager;

}

@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
Collection<Cache> caches = new ArrayList<Cache>();
if ("getOrderDetail".equals(context.getMethod().getName())) {
caches.add(caffeineCacheManager.getCache(ORDER_CACHE));
} else {
caches.add(simpleCacheManager.getCache(ORDER_PRICE_CACHE));
}
return caches;
}
}

В этом случае нам нужно переопределить метод resolveCaches интерфейса CacheResolver .

В нашем примере мы выбираем диспетчер кеша на основе имени метода. После этого нам нужно создать bean-компонент нашего пользовательского CacheResolver :

@Configuration
@EnableCaching
public class MultipleCacheManagerConfig extends CachingConfigurerSupport {

@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("customers", "orders");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.maximumSize(500)
.weakKeys()
.recordStats());
return cacheManager;
}

@Bean
public CacheManager alternateCacheManager() {
return new ConcurrentMapCacheManager("customerOrders", "orderprice");
}

@Bean
public CacheResolver cacheResolver() {
return new MultipleCacheResolver(alternateCacheManager(), cacheManager());
}
}

Теперь мы можем использовать наш пользовательский CacheResolver для разрешения диспетчера кеша для наших методов:

@Component
public class OrderDetailBO {

@Autowired
private OrderDetailRepository orderDetailRepository;

@Cacheable(cacheNames = "orders", cacheResolver = "cacheResolver")
public Order getOrderDetail(Integer orderId) {
return orderDetailRepository.getOrderDetail(orderId);
}

@Cacheable(cacheNames = "orderprice", cacheResolver = "cacheResolver")
public double getOrderPrice(Integer orderId) {
return orderDetailRepository.getOrderPrice(orderId);
}
}

Здесь мы передаем имя нашего bean -компонента CacheResolver в элементе cacheResolver .

4. Вывод

В этой статье мы узнали, как включить кэширование в нашем приложении Spring Boot. Затем мы узнали три способа использования нескольких менеджеров кеша в нашем приложении.

Как всегда, код этих примеров доступен на GitHub .