6

I'm trying to add caching on my spring-boot app by following instruction on https://www.java4s.com/spring-boot-tutorials/how-to-configure-cache-in-spring-boot-applications/, but it doesn't work. I'm not entirely sure how to test it. I have a system.out.print under controller like in this article. If cache works then it will print "test" only once but return the same result from the request with same input. I have my code as below:

CurrencyController.java

    @RequestMapping(method = RequestMethod.POST)
    @Cacheable(value="currency")
    public ResponseEntity getExchangedCurrency(final @RequestBody CurrencyExchange currencyExchange) {
        System.out.println("Test");
        return ResponseEntity.ok()
              .headers(responseHeaders)
              .body(currencyService.calculate(currencyExchange));
    }

App.java

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



    }
}

1 Answer 1

6

The way @Cacheable annotation works is utilizing method parameter as key by default for the caching map. In this case currencyExchange object. Since it's object on each request spring request dispatcher creates new object and cache manager keeps as separate key.

Req1 -> object1 -> map.put(object1, response)

Req2 -> object2 -> map.contains(object2) -> false -> map.put(object2, response)

If you think for all the post request send the same response from cache which doesn't the case always, you can change the key like this.

@RequestMapping(method = RequestMethod.POST)
@Cacheable(value="currency", key="#root.method")
public ResponseEntity getExchangedCurrency(final @RequestBody CurrencyExchange currencyExchange) {
    System.out.println("Test");
    return ResponseEntity.ok()
          .headers(responseHeaders)
          .body(currencyService.calculate(currencyExchange));
}

You can also use Spring Expression Language (SpEL) expression for defining key, if your currencyExchange has method getId() which can be used as potential cache key you can do like this

@Cacheable(value="currency", key="#root.args[0].getId()")

To clear cache Add @EnableCaching on spring boot main class, fixedDelay in milliseconds

@CacheEvict(allEntries = true, value = {"currency"})
@Scheduled(fixedDelay = 5000 ,  initialDelay = 5000)
public void clearCache() {
    System.out.println("Cache cleared");
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your reply. In CurrencyExchange there are 3 attributes: source, target and value. Is it possible to have the key that combine all these 3 values? I used this expression and it works but i'm not sure if this is the correct way. @Cacheable(value="currency", key="#root.args[0].getSource() + #root.args[0].getTarget() + #root.args[0].getValue()") . Another question is how can I make the cache expired in specified amount of time? @Pasupathi Rajamanickam
@ChandaraChea yes you can implement your key like you said, to clear cache, updated answer.
I am skeptical if the RequestMapping method would directly be cached. The reason is because Spring Cache works on the principle of building a Singleton Object of a Proxy class built on top of the current class having the @Caheable annotation. At runtime, I doubt if Spring would be able to invoke the Singleton Cache. Rather it may be creating an instance of your controller thereby skipping the cache. I think instead of caching RequestMapping methods, you should build cache on a separate method & invoke. Keep us posted on what you find.
@SriniM you're right, if we are using ehCache spring-cache does work fine doing @Cacheable on @RequestMapping

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.