如何在弹簧缓存java中配置多个缓存管理器您有一个“主”缓存管理器更细粒度的分辨率

我希望在我的Web应用程序中配置多个spring缓存管理器,并且我可以在项目的不同位置使用不同的缓存管理器。有没有办法做到这一点。


答案 1

有几种方法可以做到这一点,正确的答案取决于您对缓存的使用情况。

您有一个“主”缓存管理器

如果您将 CacheManager A 用于 90% 的用例,将 B 用于 10%,我建议为 A 创建一个默认值(您需要通过扩展指定它),如下所示:CacheManagerCacheConfigurerSupport

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Override
    @Bean // not strictly necessary
    public CacheManager cacheManager() { ... CacheManager A }

    @Bean
    public CacheManager bCacheManager() { ... CacheManager B }
}

然后,对于 10% 的用例,您可以在需要使用其他缓存管理器的类的顶部添加一个CacheConfig

@CacheConfig(cacheManager="bCacheManager")
public class MyService { /*...*/ }

如果只需要对一种方法使用其他缓存管理器,也可以在方法级别指定

@Cacheable(cacheNames = "books", cacheManager = "bCacheManager")
public Book findById(long id) { /*...*/ }

更细粒度的分辨率

如果您不处于这种情况,则需要一种方法来了解需要根据具体情况使用哪个缓存管理器。您可以根据目标类型 () 或缓存名称 () 执行此操作。您需要实现一个为您完成该转换的操作。MyServicebooksCacheResolver

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Override
    public CacheResolver cacheResolver() { ... }
}

请查看 的 javadoc 以获取更多详细信息。在实现中,您可能有几个实例(无论是否为 bean),您将根据逻辑在内部调用这些实例,以确定应使用哪个管理器。CacheResolverCacheManager

我在评论中看到您指的是“模块”。缓存实际上是一个基础结构问题,因此我强烈建议您在应用程序级别上移动该决策。您可以将缓存标记为“本地”,而将其他缓存标记为“群集”。但是,您可能应该为名称使用某种命名法,以使其更容易。不要在模块级别选择缓存管理器。

这篇博客文章用其他例子说明了这一点。


答案 2

正如@Stephane Nicoll所解释的那样,您有几种选择。我将尝试提供有关自定义的一些信息。 有一种方法:CacheResolverCacheResolver

Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);

它为可缓存操作的类,方法,参数等提供上下文。

在其基本形式中:

public class CustomCacheResolver implements CacheResolver {

    private final CacheManager cacheManager;

    public CustomCacheResolver(CacheManager cacheManager){
        this.cacheManager = cacheManager;
    }

    @Override
    public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
        Collection<Cache> caches = getCaches(cacheManager, context);
        return caches;
    }

    private Collection<Cache> getCaches(CacheManager cacheManager, CacheOperationInvocationContext<?> context) {
        return context.getOperation().getCacheNames().stream()
            .map(cacheName -> cacheManager.getCache(cacheName))
            .filter(cache -> cache != null)
            .collect(Collectors.toList());
    }
}

为了简洁起见,我在这里使用一个。但是您可以将不同的 绑定到 并进行更精细的选择:如果类名是 ,则使用 ,否则使用 。CacheManagerCacheManagerCacheResolverXGuavaCacheManagerEhCacheCacheManager

完成此步骤后,您应该注册 ,(同样,您可以在此处绑定更多内容):CacheResolverCacheManagers

@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {

    @Bean
    @Override
    public CacheManager cacheManager() {
        // Desired CacheManager
    }

    @Bean
    @Override
    public CacheResolver cacheResolver() {
        return new CustomCacheResolver(cacheManager());
    }
}

作为最后一步,您应该在其中一个 、 等注释中指定。CustomCacheResolver@Cacheable@CachePut@CacheConfig

@Cacheable(cacheResolver="cacheResolver")

您可以在此处查找代码示例。