5

My application is on Spring boot 1.5.1

I have looked up all common problems related to caching not working in spring boot (calling a cacheable method from the same class, etc) and I still can't seem to pinpoint why my method is not cacheing. I am just trying to use the simple cache built into Spring (ie the concurrent hashmap).

Setup: in pom.xml I added this

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

My configuration class is the following:

@SpringBootApplication
@Configuration
@EnableCaching
@EnableScheduling
public class Application {
    public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
    }

}

I have a controller class that has the following method to get a list of versions.

 @RequestMapping(value = "/getVersionList", method = RequestMethod.GET)
 public JSONObject getVersionList() {
    JSONObject retJSON = new JSONObject();
    List<String> versions = fetchVersionService.getVersionList();
    retJSON.put("versions", versions);
    return retJSON;
}

And the FetchVersionService class where I have the cacheable method to cache this versions list

@Cacheable("versions")
public List<String> getVersionList() {
    System.out.println("If there is something in the cache, it should not hit here.");
    return randomService.getVersions(); //another service class that gets versions from a remote location, which takes a long time
}

Whenever I make multiple GET calls to this function, it always goes inside the function even though I only expect to it execute the function once. For some reason it isn't cacheing the results. Any ideas where I went wrong with my setup? Thanks a lot.

7
  • see baeldung.com/spring-cache-tutorial - where is your CacheManager defined? Commented Feb 7, 2019 at 3:01
  • @ScaryWombat I didn't explicitly define a CacheManager. My understanding is in Spring Boot with @EnableCaching, if no CacheManager is found Spring Boot automatically sets one up for you. However I tried to define my own, still not working - codeboje.de/caching-spring-boot Commented Feb 7, 2019 at 3:09
  • 1
    Your code seems correct. More details of code can help to find out out mistake. Some things that I can think of is : 1.) check your imports . 2.) Bean scope Commented Feb 7, 2019 at 6:29
  • I imported the wrong package. Thank you so much for pointing that out, can't believe that was the issue. Commented Feb 7, 2019 at 15:19
  • @irfanhasan what package was wrong? I have the same issue Commented Jan 26, 2021 at 22:25

3 Answers 3

13

In the comments under this question @irfanhasan mentions that they had imported the wrong package but there was no certain response. I faced the same problem. I tried to use @Cachable annotation but it wasn't work. I found that it was imported as:

import springfox.documentation.annotations.Cacheable

Instead of:

import org.springframework.cache.annotation.Cacheable;

Look carefully for your IDE imports.

Sign up to request clarification or add additional context in comments.

Comments

2

Below is an End to end working code to show case Caching implementation using SpringBoot.

@Cacheable("movies")
  public List<String> getMoviesList() {
   //logic to fetch movies using API call over webClient
  return moviesList;
}

Now this code makes the response of getMoviesList cacheable due to annotation @Cacheable("movies") However this is not enough, as it needs bean of CacheManager as well. In SpringBoot this is simplified, so all you need is @EnableCaching This annotation can go in your main class with @SpringBootApplication as shown below

@SpringBootApplication
@ConfigurationPropertiesScan
@EnableCaching
public class MoviesApplication {
  public static void main(final String[] args) {
    SpringApplication.run(MoviesApplication.class, args);
  }
}

Now depending on your business workflow, you can decide the cache eviction policy.

@CacheEvict(value = "movies", allEntries = true)
  @Scheduled(fixedDelay = 12, timeUnit = TimeUnit.HOURS)
  public void evictMoviesFromCache() {
    // Nothing to do. Annotations cover functionality
    log.info("Evicting Movies from cache.");
  }

Above code evicts the code at scheduled interval of 12 hrs.

Alternatively, you could evict it manually, as shown below.

@Component
public class CacheManagerService {
  @CacheEvict("movies")
  public void evictMoviesFromCache(final String networkRef) {
    // nothing to add as this method is to evict the cache
  }
}

And Autowire CacheManagerService in your code and invoke the method explicitly. for e.g.

@Service
@RequiredArgsConstructor
@Slf4j
public class MoviesCacheManager {
  private final CacheManagerService cacheManagerService;
  private final MoviesClient moviesClient;

public List<Location> refreshMovies() {
    cacheManagerService.evictMoviesFromCache();
    var movies = moviesClient.getMovies().collectList().block();
    return Optional.ofNullable(movies).orElse(emptyList());
  }
}

Reference: https://www.baeldung.com/spring-cache-tutorial

Comments

1

In the comments under this question, @irfanhasan mentions that they had imported the wrong package and @xetra11 replied asking which package was wrong which there was no reply to. I am not @irfanhasan but it might have been the following mixup: "You can also use the standard JSR-107 (JCache) annotations (such as @CacheResult) transparently. However, we strongly advise you to not mix and match the Spring Cache and JCache annotations."

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.