简体   繁体   中英

Spring Boot @Cacheable does not serve requests from in-memory cache

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM