Using Multiple Cache Managers in Spring – 在Spring中使用多个缓存管理器

最后修改: 2020年 4月 29日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll learn how we can configure multiple cache managers in a Spring application.

在本教程中,我们将学习如何在一个Spring应用程序中配置多个缓存管理器。

2. Caching

2.缓存

Spring applies caching to methods so that our application doesn’t execute the same method multiple times for the same input.

Spring对方法进行了缓存,这样我们的应用程序就不会对相同的输入多次执行同一个方法。

It’s very easy to implement caching in a Spring application. This can be done by adding the @EnableCaching annotation in our configuration class:

在Spring应用程序中实现缓存非常容易。这可以通过在我们的配置类中添加@EnableCaching注解来实现。

@Configuration
@EnableCaching
public class MultipleCacheManagerConfig {}

Then we can start caching the output of a method by adding the @Cacheable annotation on the method:

然后我们可以通过在方法上添加@Cacheable注解来开始缓存方法的输出。

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

As soon as we add the above configuration, Spring Boot itself creates a cache manager for us.

只要我们加入上述配置,Spring Boot本身就会为我们创建一个缓存管理器。

By default, it uses ConcurrentHashMap as the underlying cache if we’ve not specified any other explicitly.

默认情况下,如果我们没有明确指定任何其他缓存,它会使用ConcurrentHashMap作为基础缓存

3. Configuring Multiple Cache Managers

3.配置多个缓存管理器

In some cases, we might need to use more than one cache manager in our application. So, let’s see how we can do this in our Spring Boot application using an example.

在某些情况下,我们可能需要在我们的应用程序中使用一个以上的缓存管理器。因此,让我们通过一个例子来看看我们如何在Spring Boot应用程序中做到这一点。

In our example, we’ll use a CaffeineCacheManager and a simple ConcurrentMapCacheManager.

在我们的例子中,我们将使用一个CaffeineCacheManager和一个简单的ConcurrentMapCacheManager

CaffeineCacheManager is provided by the spring-boot-starter-cache starter. It’ll be auto-configured by Spring if Caffeine is present, which is a caching library written in Java 8.

CaffeineCacheManager是由spring-boot-starter-cache启动器提供。如果Caffeine存在,它将被Spring自动配置,这是一个用Java 8编写的缓存库。

ConcurrentMapCacheManager uses an implementation of the cache using ConcurrentHashMap.

ConcurrentMapCacheManager使用ConcurrentHashMap来实现缓存。

We can do this in the following ways.

我们可以通过以下方式做到这一点。

3.1. Using @Primary

3.1.使用@Primary

We can create two beans of cache managers in our configuration class. Then, we can make one bean primary:

我们可以在我们的配置类中创建两个缓存管理器的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");
    }
}

Now, Spring Boot will use CaffeineCacheManager as default for all the methods until we explicitly specify our alternateCacheManager for a method:

现在,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);
}

In the above example, our application will use CaffeineCacheManager for the getCustomerDetail() method. And for the getCustomerOrders() method, it’ll use alternateCacheManager. 

在上面的例子中,我们的应用程序将使用CaffeineCacheManager用于getCustomerDetail()方法。而对于getCustomerOrders()方法,它将使用alternateCacheManager。

3.2. Extending CachingConfigurerSupport

3.2.扩展CachingConfigurerSupport

Another way we can do this is by extending the CachingConfigurerSupport class and by overriding the cacheManager() method. This method returns a bean which will be the default cache manager for our application:

另一种方法是通过扩展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");
    }
}

Note that we can still create another bean called alternateCacheManager. We can use this alternateCacheManager for a method by explicitly specifying it, as we’d in the last example.

请注意,我们仍然可以创建另一个名为alternateCacheManager的bean。我们可以通过明确指定这个alternateCacheManager来为一个方法使用,就像我们在上一个例子中那样。

3.3. Using CacheResolver

3.3.使用CacheResolver

We can implement the CacheResolver interface and create a custom 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;
    }
}

In this case, we’ve got to override the resolveCaches method of the CacheResolver interface.

在这种情况下,我们必须覆盖CacheResolver接口的resolveCaches方法。

In our example, we’re selecting a cache manager based on the method name. After this, we need to create a bean of our custom CacheResolver:

在我们的例子中,我们要根据方法的名称来选择一个缓存管理器。之后,我们需要创建一个自定义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());
    }
}

Now we can use our custom CacheResolver to resolve a cache manager for our methods:

现在我们可以使用我们的自定义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);
    }
}

Here, we’re passing the name of our CacheResolver bean in the cacheResolver element.

在这里,我们在cacheResolver元素中传递我们的CacheResolverbean的名字。

4. Conclusion

4.总结

In this article, we learned how we can enable caching in our Spring Boot application. Then, we learned three ways by which we can use multiple cache managers in our application.

在这篇文章中,我们学习了如何在Spring Boot应用程序中启用缓存。然后,我们学习了三种方法,可以在我们的应用程序中使用多个缓存管理器。

As always, the code for these examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over