Search code examples
javaspringcachingspring-cachecaffeine-cache

caffeine Cache is not evicted after expireAfterAccess/expireAfterWrite


My configuration:

@Bean
public CaffeineCacheManager cacheManager() {
    return new CaffeineCacheManager();
}

@Bean
public CaffeineCache testCache() {
    return new CaffeineCache("test_cache",
            Caffeine.newBuilder()
                    .maximumSize(10000)
                    .expireAfterAccess(30, TimeUnit.SECONDS)
                    .expireAfterWrite(30, TimeUnit.SECONDS)
                    .recordStats()
                    .build());
}

test code:(read cache 3 times in a row with 45 seconds pause between reads)

static int value = 1;
    ...

    Cache testCache = cacheManager.getCache("test_cache");
    System.out.println("read " + testCache.get("myKey", () -> value++));
    try {
        Thread.sleep(45000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("read " + testCache.get("myKey", () -> value++));
    try {
        Thread.sleep(45000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("read " + testCache.get("myKey", () -> value++));

Actual result:

read 1
read 1
read 1

Expected result: Cache is evicted after 30 seconds:

read 1
read 2
read 3

What do I wrong ?

How to fix ?


Solution

  • Just fyi, CaffeineCacheManager and CaffeineCache are Spring wrappers around the real Caffeine cache.

    org.springframework.cache.caffeine.CaffeineCache implements org.springframework.cache.Cache (emphasis on packages of both)

    As to your question, CaffeineCacheManager returned from your @Bean has NO caches actually. So when you call cacheManager.getCache("test_cache"), you get a cache created by Spring on the fly, called a dynamic cache. And this cache's expireAfterAccess and expireAfterWrite are not set. Hence, the 1 you put in it is never evicted.

    To get expected behavior, you need to add CaffeineCache to the cache manager. Check my answer.