如何在spring cache java中配置多个缓存管理器
Posted
技术标签:
【中文标题】如何在spring cache java中配置多个缓存管理器【英文标题】:How to have multiple cache manager configuration in spring cache java 【发布时间】:2016-11-28 22:34:44 【问题描述】:我想在我的 web 应用程序中配置多个 spring 缓存管理器,并且我可以在项目的不同位置使用不同的缓存管理器。有没有办法做到这一点。
【问题讨论】:
到目前为止你发现了什么? 我已经在项目的一个模块中配置了 EHCacheManager,现在我想在另一个模块中使用 RedisCacheManager,但是 spring 不允许在单个应用程序上下文中拥有 2 个 CacheManager 类型的 bean。然后我在我的配置类中实现了 CachingConfigurer 以避免这个问题。但我最终在我的ApplicationContext 中只有type-EHCacheManager 上的CacheManager bean。但我的要求是创建两个 cacheManagers bean,并且我应该能够在不同的模块中使用它们。我听说过 CompositeCacheManager,不确定这是否有帮助。非常感谢 【参考方案1】:有几种方法可以做到这一点,正确的答案取决于你对缓存的使用。
你有一个“主”缓存管理器
如果您将 CacheManager A 用于 90% 的用例,而 B 用于 10%,我建议为 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 或不作为 bean),您将根据您的逻辑在内部调用它们以确定应该使用哪个管理器。
我在评论中看到您指的是“模块”。缓存实际上是一个基础设施问题,所以我强烈建议您在应用程序级别移动该决定。您可以将缓存标记为“本地”,而将其他标记为“集群”。但是您可能应该对名称进行某种命名以使其更容易。不要在模块级别选择缓存管理器。
this blog post 用其他例子说明了这一点。
【讨论】:
Stephane,我正在使用这种方法来扩展 Spring Boot 默认配置,但这似乎是解决我的问题的一种原始方法,你能建议我一个更好的方法来解决my problem 吗?谢谢 当心:在 spring-boot 1.5 中扩展 CachingConfigurerSupport 时,您将覆盖一些方法(默认 keyGenerator 和 errorHandler),这会使您的缓存无用。我使用了相同的方法而没有扩展该类。只需声明 bean 就足以让它工作。 您不必重写这些方法。否则,将使用默认的KeyGenerator
和 ErrorHandler
。
您好,感谢您的回答。除了 Spring 创建的默认缓存管理器之外,是否有可能创建一个缓存管理器?实际上,我让 Spring 使用 ehcache 自动配置 JCacheManager,我会保留默认的,而不必重新定义它。当我创建自己的缓存管理器时,由于@ConditionalOnMissingBean 而不再创建默认的缓存管理器。
请不要在评论中提问。答案是否定的,如果您创建自己的,自动配置将按原样退出。也就是说,您不必将其创建为 bean。【参考方案2】:
正如@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
s 绑定到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")
您可以查看here 以获取代码示例。
【讨论】:
【参考方案3】:您可以像这样编写客户 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")
【讨论】:
以上是关于如何在spring cache java中配置多个缓存管理器的主要内容,如果未能解决你的问题,请参考以下文章
如何在基于xml的spring配置中为hibernate.javax.cache.uri属性指定相对路径