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 啓動器提供。 如果存在 Caffeine(一種 Java 8 中編寫的緩存庫),則 Spring 會自動配置它。
ConcurrentMapCacheManager 使用 ConcurrentHashMap 實現緩存。
我們可以通過以下方式實現。
3.1. 使用 @Primary
我們可以創建配置類中兩個緩存管理器 Bean。然後,我們可以將其中一個 Bean 設置為主 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 作為默認緩存管理器,直到我們明確指定某個方法的 alternateCacheManager:
@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() 方法,它將使用 alternateCacheManager。
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");
}
}請注意,我們仍然可以創建另一個名為 alternateCacheManager 的 Bean。我們可以通過顯式指定它來使用這個 alternateCacheManager,就像在之前的示例中那樣。
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;
}
}在這種情況下,我們需要覆蓋 CacheResolver 接口中的 resolveCaches 方法。
在我們的示例中,我們通過方法名來選擇緩存管理器。之後,我們需要創建一個自定義的 CacheResolver 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");
}
@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);
}
}在這裏,我們通過將 CacheResolver Bean 傳遞到 cacheResolver 元素中。
4. 結論
在本文中,我們學習瞭如何啓用 Spring Boot 應用程序中的緩存。此外,我們還學習了通過三種方式在應用程序中使用多個緩存管理器。