javaspring-bootcaching

Spring boot cache not working as expected


I'm trying to use caffeine cache on my springboot 3.1.4 application but it seems it doesn't work at all

The method is called every time and the cache it always empty

I have my cache configuration class

@Configuration
@EnableCaching
public class CacheConfig {

  @Bean
  public Caffeine<Object, Object> caffeineConfig() {
    return Caffeine.newBuilder().expireAfterWrite(60, TimeUnit.MINUTES);
  }

  @Bean
  public CacheManager cacheManager(Caffeine<Object, Object> caffeine) {
    CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
    caffeineCacheManager.setCaffeine(caffeine);
    return caffeineCacheManager;
  }
  
}

I have a cacheable method

public class Utils {

    @Cacheable
    public Integer test (Integer id) {
        
        System.out.println("Not in cache : " + id);
        
        return id + 2;
        
    }
    
}

I'm trying to call it from a controller and print out cache content

@RestController
public class TestController {

    @Autowired
    CacheManager cacheManager;
    
    @GetMapping("/test")
    public void test() {
        
        Utils utils = new Utils();
        
        System.out.println(utils.test(3));
        System.out.println(utils.test(3));
        System.out.println(utils.test(4));
        
        CaffeineCache caffeineCache = (CaffeineCache) cacheManager.getCache("JSON");
        Cache<Object, Object> nativeCache = caffeineCache.getNativeCache();

        for (Map.Entry<Object, Object> entry : nativeCache.asMap().entrySet()) {

            System.out.println("Key = " + entry.getKey());
            System.out.println("Value = " + entry.getValue());
        }
    }
    
}

Output :

Not in cache : 3
5
Not in cache : 3
5
Not in cache : 4
6

Do you have any idea of what I'm doing wrong ?


Solution

  • Spring Boot 101: anything is SpringBoot will only work when you autowire it (checkout proxy pattern to understand why). The second you use new - none of SpringBoot magic works (because Spring works via proxying your defined classes - Spring managed beans).

    Solution: make Utils a Spring managed Component (give it a better name while you are at it):

    @Service
    public class Utils {
        @Cacheable
        public Integer test (Integer id) {
            System.out.println("Not in cache : " + id);
            return id + 2;
        }
    }
    

    And then use it via @Autowired:

    @RestController
    public class TestController {
    
        @Autowired
        CacheManager cacheManager;
    
        @Autowired
        Utils utils;
    
        @GetMapping("/test")
        public void test() {
            System.out.println(utils.test(3));
            System.out.println(utils.test(3));
            System.out.println(utils.test(4));
    
       // ...