7

I have following declaration:

@Cacheable("books")
public Book findBook(ISBN isbn) {...}

But I want to update the cache every 30 minutes. I understand that I can create @Scheduled job to invoke method annotated @CacheEvict("books")

Also, I suppose that in this case all books will be cleared but it is more desirable to update only stale data(which were put in cache > 30 minutes ago)

Is there anything in spring that can facilitate implementation?

Giorgi Beria
  • 86
  • 1
  • 11
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • See the documentation of your cache implementation (EHCache by default) and adjust the timings to evict items older than 30 minutes. – Kayaman Sep 11 '19 at 10:18
  • 1
    @Kayaman here https://spring.io/guides/gs/caching/ metntioned that default implementation uses ConcurrentHashMap – gstackoverflow Sep 11 '19 at 10:22
  • Well, that's not going to be very configurable most likely. But that's how you do it with a real cache. – Kayaman Sep 11 '19 at 10:25
  • 1
    Look into Caffeine, formerly guava cache, it has configurable time to live (TTL). Edit to add: here's a good link: https://www.baeldung.com/java-caching-caffeine I'd avoid coding to solve this, should be a cache config solution imo. – Taylor Sep 12 '19 at 13:49

1 Answers1

1

Cache implementations provide a feature named expire after write or time to life for this task. The different cache implementations have a lot variances. In Spring no effort was made to try to abstract or generalize the configuration part as well. Here is an example of programmatic configuration for your cache in Spring, if you like to use cache2k:

@Configuration
@EnableCaching
public class CachingConfig extends CachingConfigurerSupport  {

  @Bean
  public CacheManager cacheManager() {
    return new SpringCache2kCacheManager()
      .addCaches(
        b->b.name("books").keyType(ISBN.class).valueType(Book.class)
            .expireAfterWrite(30, TimeUnit.MINUTES)
            .entryCapacity(5000);
  }
}

More information about this is in cache2k User Guide - Spring Framework Support. Other cache implementations like, EHCache or Caffeine support expiry as well, but the configuration is different.

If you like to configure the cache expiry in a "vendor neutral" way, you can use a cache implementation that support the JCache/JSR107 standard. The standard includes setting an expiry. A way to do it, looks like this:

@Configuration
@EnableCaching
public class CacheConfiguration {

  @Bean
  public JCacheCacheManager cacheManager() {
    return new JCacheCacheManager() {
      @Override
      protected Collection<Cache> loadCaches() {
        Collection<Cache> caches = new ArrayList<>();
        caches.add(new JCacheCache(
          getCacheManager().createCache("books",
          new MutableConfiguration<ISBN,Book>()
            .setExpiryPolicyFactory(ModifiedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 30)))),
          false));
        return caches;
      }
    };
  }
}

The in JCache is, that there are configuration options, that you need, which are not part of the standard. One example is limiting the cache size. For this, you always need to add a vendor specific configuration. In case of cache2k (I am the author of cache2k), which supports JCache, the configurations are merged, which is described in detail at cache2k User Guide - JCache. This means on a programmatic level you do the "logic" part of the configuration, where as, the "operational" part like the cache size is configurable in an external configuration file.

Unfortunately, its not part of the standard how a vendor configuration and a programmatic configuration via the JCache API needs to interoperate. So, even a 100% JCache compatible cache might refuse operation, and require that you only use one way of configuration.

cruftex
  • 5,545
  • 2
  • 20
  • 36