1

Given the following method with the Cacheable annotation:

    @Cacheable(value = "cachekey", key = "#taskId")
    public Task getTask(Long taskId) {
        log.info("called");
        Task task = ...;
        return task;
    }

And the following configuration:

@EnableCaching
@Configuration
public class CacheConfiguration {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("cachekey");
    }

    @Scheduled(fixedDelay = 30000)
    @CacheEvict(allEntries = true, cacheNames = {"cachekey"})
    public void cacheEvict() {
    }
}

And the following pom parts:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/>
    </parent>
...
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

By calling getTask, I always hit the method and no request is served from the cache itself.

What am I doing wrong?

Gábor DANI
  • 2,063
  • 2
  • 22
  • 40
  • A good first step if you haven't already might be to enable TRACE logging on Spring Cache. I believe doing so will log cache keys, hits, misses, etc. https://stackoverflow.com/q/37281139/1526322 – Knox May 16 '22 at 22:20

1 Answers1

1

I've recreated an application based off the code you provided and tried to keep it as similar as possible. The program yields the output:

Calling getTask
getTask called
Calling getTask again
true

Which indicates that getTask is only executed once and that the caching is working. So we'll have to assume it is something not listed in the code you provided. Two thoughts come to mind:

  1. Are you sure that you are providing the same long to #getTask(Long) when calling it multiple times? As it's currently configured, different longs will result in different cache entries. You'll have to call it at least twice with the same long in order to see caching take effect.
  2. Are you calling #getTask(Long) from a different bean than the one which contains #getTask(Long)? The functionality provided by @Cacheable is implemented using Spring AOP. Spring AOP will wrap the bean (CachedService in my example) with some generated code that handles the cache retrieval and put. However, this wrapping does not affect method calls internal to that bean.

For example, if I added a #getTask99() method to CachedService like in the code snippet below:

@Component
public static class CachedService {
    public Task getTask99() {
        return getTask(99L);
    }

    @Cacheable(value = "cachekey", key = "#taskId")
    public Task getTask(Long taskId) {
        System.out.println("getTask called");
        Task task = new Task(System.out::println);
        return task;
    }
}

Calling #getTask99() produces:

Calling getTask99
getTask called
Calling getTask99 again
getTask called
false

Indicating that nothing was cached, as the bean wrapping has been circumvented. Instead, call #getTask(99L) from a different bean, like CacheTestRunner in my example.

Knox
  • 1,150
  • 1
  • 14
  • 29