简体   繁体   English

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

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

I want to have multiple spring cache managers configured in my web-application and I would be able to use different cache manager at various places in my project.我想在我的 web 应用程序中配置多个 spring 缓存管理器,我将能够在我的项目的不同位置使用不同的缓存管理器。 Is there any way to do this.有没有办法做到这一点。

There are several ways you can do this and the right answer depends on your usage of the cache.有几种方法可以做到这一点,正确的答案取决于您对缓存的使用。

You have a "main" cache manager你有一个“主”缓存管理器

If you use CacheManager A for 90% of your use case and B for 10% I'd advise to create a default CacheManager for A (you'll need to specify it via a CacheConfigurerSupport extension), something like:如果您在 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 }
}

Then for the 10% use case you add a CacheConfig at the top of the classes that need to use the other cache manager然后对于 10% 的用例,您在需要使用其他缓存管理器的类的顶部添加一个CacheConfig

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

If you need to use the other cache manager for only one method, you can specify that at method level as well如果您只需要为一个方法使用另一个缓存管理器,您也可以在方法级别指定

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

More fine grained resolution更细粒度的分辨率

If you're not in this situation, you need a way to know which cache manager needs to be used on a case-by-case basis.如果您不在这种情况下,您需要一种方法来了解需要根据具体情况使用哪个缓存管理器。 You can do that based on the target type ( MyService ) or the name of the cache ( books ).您可以根据目标类型 ( MyService ) 或缓存名称 ( books ) 执行此操作。 You'll need to implement a CacheResolver that does that translation for you.您需要实现一个为您进行翻译的CacheResolver

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

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

Check the javadoc of CacheResolver for more details.查看CacheResolver的 javadoc 以获取更多详细信息。 In the implementation, you may have several CacheManager instances (either as bean or not) that you'll call internally based on your logic to determine which manager should be used.在实现中,您可能有多个CacheManager实例(无论是否作为 bean),您将根据您的逻辑在内部调用它们以确定应该使用哪个管理器。

I saw in a comment that you were referring to "module".我在评论中看到您指的是“模块”。 Caching is really an infrastructure matter so I'd strongly advice you to move that decision at the application level.缓存实际上是一个基础架构问题,因此我强烈建议您在应用程序级别移动该决定。 You may tag cache as being "local" and others being "clustered".您可以将缓存标记为“本地”,而将其他缓存标记为“集群”。 But you should probably have some kind of nomenclature for the name to make it easier.但是您可能应该为名称使用某种命名法,以使其更容易。 Don't choose a cache manager at the module level.不要在模块级别选择缓存管理器。

this blog post illustrates this with other examples. 这篇博文用其他例子说明了这一点。

As @Stephane Nicoll explained, you have several options.正如@Stephane Nicoll 所解释的,您有多种选择。 I will try to give some info on custom CacheResolver .我将尝试提供有关自定义CacheResolver一些信息。 CacheResolver has one method: CacheResolver有一种方法:

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

which gives context to the cacheable operation's class, method, arguments etc.它为可缓存操作的类、方法、参数等提供上下文。

In its basic form:在其基本形式中:

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

Here I am using one CacheManager for brevity.为简洁起见,我在这里使用了一个CacheManager But you can bind different CacheManager s to CacheResolver and make more granular selections: if class name is X , then use GuavaCacheManager , otherwise use EhCacheCacheManager .但是您可以将不同的CacheManager绑定到CacheResolver并进行更精细的选择:如果类名是X ,则使用GuavaCacheManager ,否则使用EhCacheCacheManager

After this step, you should register CacheResolver , (again you can bind more CacheManagers here):在这一步之后,你应该注册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());
    }
}

And as the last step, you should specify CustomCacheResolver in one of @Cacheable , @CachePut , @CacheConfig etc. annotations.作为最后一步,您应该在@Cacheable@CachePut@CacheConfig等注释之一中指定CustomCacheResolver

@Cacheable(cacheResolver="cacheResolver")

You can look here for code samples.您可以在此处查看代码示例。

you can write a customer CacheManager bean just like this您可以像这样编写客户 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;
    }

then use this in your annoations like this然后像这样在您的注释中使用它

 @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