javaspring-bootcachingspring-cache

Annotation @CachePut not working, but method .put does


I tried the annotation @CachePut in the method updateCategoryCacheForCountry and it wasn't working. But when doing so programatically by getting the cache and using .put it works fine. What could be the reason? I'm using Spring Cache. The method is being called by a @Scheduled method.

//    @CachePut(key = "#country")
    public CacheCategories updateCategoryCacheForCountry(String country) {
        CacheCategories categories = requestDirectus(country);

        Cache categoriesCache = cacheManager.getCache("categories");
        categoriesCache.put(country, categories);

        return categories;
    }
    @Scheduled(fixedDelay = 300000) //5m
    protected void updateCategories() {
        String[] countries = {esConfig.getStoreArgentina(), esConfig.getStoreChile(), esConfig.getStoreParaguay(), esConfig.getStoreBolivia()};

        for (String country : countries) {
            updateCategoryCacheForCountry(country);
        }
    }
@EnableCaching
@Configuration
@EnableScheduling
public class CacheConfig {
    
  @Bean // Configuramos el cache a utilizar
  public CacheManager cacheManager() {
      SimpleCacheManager cacheManager = new SimpleCacheManager();
      cacheManager.setCaches(Arrays.asList(
        new ConcurrentMapCache("categories"),
        new ConcurrentMapCache("token")
      ));
      return cacheManager;
  }
}

Solution

  • It is caused because you are making an internal call from the same class to another internal method of the same class of a spring bean.

    Doing so, the actual call you are making to updateCategoryCacheForCountry is not directed towards the spring proxy class that contains the boilerplate code to handle the annotation @CachePut but instead is directed towards your own simple class and hence the functionality of @CachePut does not exist in your implemented code in your own class.

    Because of the above you observe that the manualy written code inside your method, work as expected, for the cache functionality, but the annotation outside of this method does not work as it was expected to work. This is because the annotation was expected to build a boilerplate code similar to what you have done inside your method body, but because the method called is not from the spring proxy, this boilerplate code simply does not exist.

    You can read more about these type of issues here -> spring documentation

    Solution

    You would need to create another class, make it a spring bean and then call the method from the original class.

        @Service
        public class SchedulerClass {
    
         @Autowired
         private MyCacheImpl myCacheImpl;
        
         @Scheduled(fixedDelay = 300000) //5m
            protected void updateCategories() {
                String[] countries = {esConfig.getStoreArgentina(), esConfig.getStoreChile(), esConfig.getStoreParaguay(), esConfig.getStoreBolivia()};
        
                for (String country : countries) {
                    myCacheImpl.updateCategoryCacheForCountry(country); <--------
                }
            }
        }
    

    And then

     @Service
     public class MyCacheImpl {
    
    
        @CachePut(key = "#country")
        public CacheCategories updateCategoryCacheForCountry(String country) {
            CacheCategories categories = requestDirectus(country);
            return categories;
        }
    }