繁体   English   中英

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

[英]How to have multiple cache manager configuration in spring cache java

我想在我的 web 应用程序中配置多个 spring 缓存管理器,我将能够在我的项目的不同位置使用不同的缓存管理器。 有没有办法做到这一点。

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

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

如果您在 90% 的用例中使用 CacheManager A,在 10% 中使用 B,我建议为 A 创建一个默认的CacheManager (您需要通过CacheConfigurerSupport扩展指定它),例如:

@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) { /*...*/ }

更细粒度的分辨率

如果您不在这种情况下,您需要一种方法来了解需要根据具体情况使用哪个缓存管理器。 您可以根据目标类型 ( MyService ) 或缓存名称 ( books ) 执行此操作。 您需要实现一个为您进行翻译的CacheResolver

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

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

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

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

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

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

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

@Cacheable(cacheResolver="cacheResolver")

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

您可以像这样编写客户 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")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM