安排Spring缓存清除计划?

34

是否可以将Spring缓存驱逐计划安排在每天午夜?

我已经阅读了Spring缓存文档,但没有找到关于定时缓存驱逐的内容。

我需要每天清除缓存并在我的应用程序之外进行更改时重新缓存它。


未来的访客们,小心了……这些答案很混乱。我不得不混合2~3个答案才能弄对。 - user2652379
1
正确答案是什么?你能发一下吗? - CSKR
8个回答

45

尝试使用@Scheduled 示例:

@Scheduled(fixedRate = ONE_DAY)
@CacheEvict(value = { CACHE_NAME })
public void clearCache() {  
    log.debug("Cache '{}' cleared.", CACHE);    
}

您也可以在@Scheduled中使用cron表达式。


1
它对我没用,我讨厌将其拆分为两个组件和两种不同的方法。我不得不创建另一个组件(ClearCacheScheduler),使用仅Scheduled注释的方法,然后调用我的服务组件中CacheEvict注释的clearCache()方法。 - Celebes
2
这个不起作用。Scheduled和CacheEvict必须在不同的类/方法中。 - voliveira89
14
在应用程序类中不要忘记添加@EnableScheduling - Drakes
2
@Zon 只需添加一条注释,例如 "//无事可做"。 - Oleksandr Bondarchuk
2
@Zon日志语句? - java-addict301
显示剩余4条评论

15

如果您在带有参数的方法上使用@Cacheable注释,则在@CacheEvict上永远不要忘记allEntries=true注释属性,否则您的调用将仅从缓存中删除您提供给clearCache() 方法的键参数,这意味着您将无法从缓存中删除任何内容。


6
也许不是最优雅的解决方案,但@CacheEvict无法工作,所以我直接使用了CacheManager
该代码通过调度程序清除名为foo的缓存。
class MyClass {

    @Autowired CacheManager cacheManager;

    @Cacheable(value = "foo")
    public Int expensiveCalculation(String bar) {
        ...
    }

    @Scheduled(fixedRate = 60 * 1000);
    public void clearCache() {
        cacheManager.getCache("foo").clear();
    }
}

但是你能否在这里使用带参数的 clearCache,这样 "foo" 就不会被硬编码了吗? - zygimantus

3
请按照以下代码更改cron表达式。我已经将其设置为3分钟。
  1. Create a class.

  2. Use the below method inside the class.

    class A 
    {
    @Autowired CacheManager cacheManager;
    
    @Scheduled(cron ="0 */3 * ? * *")
        public void cacheEvictionScheduler()
        {
             logger.info("inside scheduler start");
            //clearCache();
             evictAllCaches();
            logger.info("inside scheduler end");
        }
    
    public void evictAllCaches() {
             logger.info("inside clearcache");
            cacheManager.getCacheNames().stream()
              .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
        }
    }
    

2
我知道这个问题很旧,但我找到了一个更好的解决方案适用于我。也许这可以帮助其他人。
因此,确实可以进行定期缓存清除。以下是我在我的情况下所做的。
注释@Scheduled和@CacheEvict似乎无法一起工作。 因此,您必须将调度方法和缓存清除方法分开。 但由于整个机制基于代理,因此只有对类的公共方法的外部调用才会触发缓存清除。这是因为同一类中两个方法之间的内部调用不经过Spring代理。
我设法以与Celebes(请参见评论)相同的方式修复它,但改进了避免使用两个组件。
@Component
class MyClass
{

    @Autowired
    MyClass proxiedThis; // store your component inside its Spring proxy.

    // A cron expression to define every day at midnight
    @Scheduled(cron ="0 0 * * *")
    public void cacheEvictionScheduler()
    {
        proxiedThis.clearCache();
    }

    @CacheEvict(value = { CACHE_NAME })
    public void clearCache()
    {
        // intentionally left blank. Or add some trace info.
    }    
}

不要让大家感到困惑。@Scheduled@CacheEvict可以一起使用。对于内部bean调用,您还可以使用applicationContext.getBean(MyClass.class).clearCache() - sjngm
1
看起来至少有两个人在这里没有成功。你使用的是哪个版本的Spring Boot?(或者Spring) - bugsbuRny
我使用Spring Boot 2.0.5。我认为它与版本无关,因为@Scheduled@CacheEvict已经存在一段时间了。如果不起作用,那么通常是来自另一个角落的某些其他副作用。你可以尝试使用一个非常简单的项目,并添加一个带有两个注释以及@EnableScheduling@EnableCaching的方法。 - sjngm
当我的配置类停止扩展CachingConfigurerSupport并变成了一个常规的配置类时(我在@Configuration类中有该方法),原始答案开始运行。 - eis

2
使用注解@Scheduled和cron表达式以及@CacheEvict和allEntries = true,可以像这样编写代码:
/*
* This clears the entire cache called "myCache" everyday, 
* at 00.00 (am) in the time zone of the server.
*/
@Scheduled(cron = "0 0 0 * * ?")
@CacheEvict(value = "myCache", allEntries = true)
public void clearMyCache() {}

如果您想在清除缓存之前添加逻辑,可以在方法体中实现:
/*
* This clears the entire cache called "myCache" everyday, 
* at 00.00 (am) in the time zone of the server.
*/
@Scheduled(cron = "0 0 0 * * ?")
@CacheEvict(value = "myCache", allEntries = true)
public void clearMyCache() {

    // Add logic here
    log.debug("Clearing myCache now");

}

CacheEvict会在您的代码运行后发生,仅当它不抛出任何异常时才会发生。您可以通过添加"beforeInvocation = true"来更改这一点,在这种情况下,它首先清除缓存,然后运行您的代码。


1

Spring缓存框架是事件驱动的,即只有在调用相应方法时才会触发@Cacheable@CacheEvict

但是,您可以利用底层缓存提供程序(请记住,Spring缓存框架仅是一个抽象,本身不提供缓存解决方案)来自行使缓存失效。例如,EhCache具有一个属性,即timeToLiveSeconds,它规定了缓存保持活动状态的时间。但是,除非调用@Cacheable注释的方法,否则这不会为您重新填充缓存。

因此,对于特定时间(如午夜)的缓存清除和重新填充,请考虑在Spring中实现后台scheduled service,以按需触发缓存清除和重新填充。预期行为不是开箱即用的。

希望这可以帮助您。


明天早上我会尝试并回复您结果。 - Philippe Gioseffi
我之前有一些其他的事情需要优先处理,现在我再次开始处理这个用例。很抱歉没能及时回复。我会立即回来给你答复! - Philippe Gioseffi
没关系,我只是好奇这种方法是否有帮助 :) - Bond - Java Bond
实际上,上面的答案帮了我! - Philippe Gioseffi

0
你可以定义一个定时缓存清除,它可以根据cron表达式工作。
例如,下面的代码将清除缓存。
@CacheEvict(value = "movieList", allEntries = true)
  @Scheduled(cron = "@midnight", zone = "UTC")
  public void evictMoviesCache() {
    // Nothing to do. Cache eviction schedule, you can optionally log here.
  }

另一种变化是
   @CacheEvict(value = "movieList", allEntries = true)
   @Scheduled(fixedDelay = 12, timeUnit = TimeUnit.HOURS)
      public void evictMoviesCache() {
        // Nothing to do. Cache eviction schedule, you can optionally log here.
      }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接