如何在spring cache java中配置多个缓存管理器

时间:2016-07-25 14:17:09

标签: java spring caching spring-boot spring-cache

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

3 个答案:

答案 0 :(得分:26)

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

你有一个"主要"缓存管理器

如果你使用CacheManager A占用率的90%而B占10%,我建议为A创建默认CacheManager(你需要通过{指定它) {1}}扩展名),类似于:

CacheConfigurerSupport

然后对于10%的用例,在需要使用其他缓存管理器的类的顶部添加@Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { @Override @Bean // not strictly necessary public CacheManager cacheManager() { ... CacheManager A } @Bean public CacheManager bCacheManager() { ... CacheManager B } }

CacheConfig

如果您只需要将一个其他缓存管理器用于一个方法,您也可以在方法级别指定

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

更精细的分辨率

如果您不处于这种情况,则需要一种方法来了解需要根据具体情况使用哪个缓存管理器。您可以根据目标类型(@Cacheable(cacheNames = "books", cacheManager = "bCacheManager") public Book findById(long id) { /*...*/ } )或缓存名称(MyService)执行此操作。您需要实现为您执行该翻译的books

CacheResolver

检查@Configuration @EnablleCaching public class CacheConfig extends CachingConfigurerSupport { @Override public CacheResolver cacheResolver() { ... } } 的javadoc以获取更多详细信息。在实现中,您可能有几个CacheResolver实例(无论是否为bean),您将根据您的逻辑在内部调用以确定应使用哪个管理器。

我在评论中看到你指的是" module"。缓存实际上是一个基础架构问题,所以我强烈建议您在应用程序级别上移动该决策。您可以将缓存标记为" local"和其他人一起"聚集"。但是你应该对名称有一些命名,以使其更容易。不要在模块级别选择缓存管理器。

this blog post通过其他示例说明了这一点。

答案 1 :(得分:5)

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

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());
    }
}

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

完成此步骤后,您应该注册CacheResolver,(再次,您可以在此处绑定更多CacheManagers):

@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")

您可以查看here代码示例。

答案 2 :(得分:0)

您可以像这样编写客户CacheManager bean

    @Primary
    @Bean("customerCacheManager")
    public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
        Map<String, Long> expires = new HashMap<>();
        expires.put("fundShareSplit", TimeUnit.SECONDS.toSeconds(60));
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);
        cacheManager.setExpires(expires);
        List<String> cacheNames = Arrays.asList("fundShareSplit");
        cacheManager.setCacheNames(cacheNames);
        return cacheManager;
    }

然后像这样在您的注释中使用

 @Cacheable(cacheManager = "customerCacheManager",value = "fundShareSplit",key="'smile:asset:fundSplit:fundId:'+#root.args[0]+'_localDate:'+#root.args[1]",unless="#result == null")