java Spring Cache - 创建自定义 CacheManager

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37784371/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 02:48:08  来源:igfitidea点击:

Spring Cache - Create custom CacheManager

javaspring-bootehcachespring-cache

提问by Oleg

I'm using Spring Boot and EhCache to develop a calendar application. I'm trying to cache the following method:

我正在使用 Spring Boot 和 EhCache 来开发日历应用程序。我正在尝试缓存以下方法:

@Override
@Cacheable(value = "concerts")
public List<Event> getEvents(String eventsForUser, Date startDate, Date endDate) throws Exception {
    return fetchEventsFromTheServer(eventsForUser, startDate, endDate);
}

The challenge is I would like to manipulate returned cached result. For example, check if there is cache for given dates but for a different user and then return it instead (as long as both users meet certain criteria).

挑战是我想操纵返回的缓存结果。例如,检查给定日期是否有缓存但对于不同的用户,然后将其返回(只要两个用户都满足某些条件)。

So, before returning a result I would like:

所以,在返回结果之前,我想:

  • to get a list of all cached entries
  • loop through all of them and check for needed dates/users
  • if found suitable - return that
  • if not found - cache is not available, run the method.
  • 获取所有缓存条目的列表
  • 遍历所有这些并检查所需的日期/用户
  • 如果发现合适 - 返回
  • 如果未找到 - 缓存不可用,请运行该方法。

I think the best would be to create a custom Cache Manager which will do all the manipulation with cached concert and use default auto configured cache for all other methods, but I can't get my custom manager to work and didn't find any good example on how to implement a custom CacheManager.

我认为最好的办法是创建一个自定义缓存管理器,它将使用缓存的 Concert 进行所有操作,并为所有其他方法使用默认的自动配置缓存,但我无法让我的自定义管理器工作,也没有找到任何好处关于如何实现自定义 CacheManager 的示例。

Here is what I have:

这是我所拥有的:

Application.java:

应用程序.java:

@SpringBootApplication
@ComponentScan
@EnableCaching
@EnableScheduling
public class SpringBootWebApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootWebApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class<SpringBootWebApplication> applicationClass = SpringBootWebApplication.class;


    @Bean(name = "eventsCacheManager")
    public EventsCacheManager eventsCacheManager() {

        return new EventsCacheManager();
    }

    @Primary
    @Bean(name = "cacheManager")
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheCacheManager().getObject());
    }

    @Bean
    public EhCacheManagerFactoryBean ehCacheCacheManager() {
        EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
        cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
        cmfb.setShared(true);
        return cmfb;
    }


}

EventsCacheManager.java

事件缓存管理器.java

@Component
public class EventsCacheManager implements CacheManager  {

    @Override
    public Cache getCache(String s) {
        return null;
    }

    @Override
    public Collection<String> getCacheNames() {
        return null;
    }
}

EventsCacheManager.java - how to implement it?

EventsCacheManager.java - 如何实现它?

@Component
public class EventsCacheManager implements CacheManager  {

    @Override
    public Cache getCache(String s) {
        return null;
    }

    @Override
    public Collection<String> getCacheNames() {
        return null;
    }
}

I would really appreciate if someone can give me an example on how I should implement my custom CacheManager

如果有人能给我一个关于如何实现我的自定义的例子,我将不胜感激 CacheManager

回答by John Blum

I did not spend much time thinking about your requirements/use case, but I do think a custom CacheManagerwould work in this situation, assuming the "custom" CacheManagerlogic is correct.

我没有花太多时间考虑您的需求/用例,但我确实认为CacheManager在这种情况下自定义会起作用,假设“自定义”CacheManager逻辑是正确的。

So, by default, Springlooks for a bean in the context with the name "cacheManager" and uses it for all cached operations. In your configuration, you clearly have 2 "CacheManagers" defined...

因此,默认情况下,Spring在上下文中查找名为“cacheManager”的 bean,并将其用于所有缓存操作。在您的配置中,您显然定义了 2 个“CacheManagers”...

@Bean(name = "eventsCacheManager")
public EventsCacheManager eventsCacheManager() {

    return new EventsCacheManager();
}

@Primary
@Bean(name = "cacheManager")
public CacheManager cacheManager() {
    return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}

I.e. the "eventsCacheManager" (custom) and "cacheManager" (standard). Indeed, you even marked the "cacheManager" as primary (using the @Primaryannotation). Of course, had you not done that, Springwould certainly have complained since more than 1 bean of a given type (i.e. CacheManager) was found in the context when performing auto-wiring (which defaults to auto-wire by type).

即“eventsCacheManager”(自定义)和“cacheManager”(标准)。事实上,您甚至将“cacheManager”标记为主要(使用@Primary注释)。当然,如果您没有这样做,Spring肯定会抱怨,因为CacheManager在执行自动装配(默认为按类型自动装配)时在上下文中发现了超过 1 个给定类型(即)的bean 。

So, in order to call out which cache management strategy (i.e. CacheManager) to use at runtime with a particular service call, you also need to tell Springwhich CacheManager(aka strategy) to use, like so...

因此,为了CacheManager在特定服务调用中调用在运行时使用的缓存管理策略(即),您还需要告诉Spring 使用哪个CacheManager(又名策略),就像这样......

@Override
@Cacheable(value = "concerts", cacheManager="eventsCacheManager")
public List<Event> getEvents(String eventsForUser, Date startDate, Date endDate) throws Exception {
    return fetchEventsFromTheServer(eventsForUser, startDate, endDate);
}

I.e. using the cacheManagerattribute in the @Cacheableannotation to indicate which caching strategy to use.

即使用注释中的cacheManager属性@Cacheable来指示使用哪种缓存策略。

See Spring's Reference Doc on Custom cache resolutionfor more details.

有关更多详细信息,请参阅 Spring 关于自定义缓存解析的参考文档。

Hope this helps get you going.

希望这有助于你前进。

回答by Louis Jacomet

From my understanding of your question, I believe you are looking at the problem the wrong way.

根据我对你的问题的理解,我相信你看问题的方式是错误的。

Instead of having to browse cache contents to extract derived information, you should insert into the cache the derived information at the time of loading the main data.

不必浏览缓存内容来提取派生信息,您应该在加载主要数据时将派生信息插入缓存。

For example, when loading month based information, break it immediately into day based information and put that in a cache as well.

例如,在加载基于月份的信息时,立即将其分解为基于日期的信息并将其放入缓存中。

This description also should clearly indicate that what you want to do is beyond the capabilities of the Spring caching abstraction, as you need custom cache loading logic.

这个描述还应该清楚地表明你想要做的超出了 Spring 缓存抽象的能力,因为你需要自定义缓存加载逻辑。

So I would not recommend hacking a CacheManagerto hide that logic but instead do it from the data loading logic.

所以我不建议破解 aCacheManager来隐藏该逻辑,而是从数据加载逻辑中进行。