I have a singleton class (@Service annotated). This class has a method which takes 200/300ms to execute.
This method is annotated with @Cacheable and synchronized.
@Cacheable(value="nextPlaying", key = "#startingFrom.getYear() + #startingFrom.getMonth() + #startingFrom.getDay() + #startingFrom.getHours() + #startingFrom.getMinutes() + #locale.getLanguage()")
public synchronized List<Match> getNextPlaying(Date startingFrom, Locale locale)
By launching multiple threads calling this method I see that for these 200/300ms until the result isn't cached, it executes again and again the method until is cached. Seems that @Cacheable annotation doesn't take synchronized into account... Is this a bug?
The sync parameter says: Synchronize the invocation of the underlying method if several threads are attempting to load a value for the same key.
Annotation indicating that the result of invoking a method (or all methods in a class) can be cached. Each time an advised method is invoked, caching behavior will be applied, checking whether the method has been already invoked for the given arguments.
The @Cacheable annotation takes care of putting the result into the cache. After the first call, the cached value is in the cache and stays there according to the cache configuration. When the method is called the second time, and the cache value has not been evicted yet, Spring will search for the value by the key.
The Cacheable annotation takes three arguments: value, which is mandatory, together with key and condition. The first of these, value, is used to specify the name of the cache (or caches) in which the a method's return value is stored.
Support for synchronized caches is added in Spring 4.3: spring.io/blog/2016/03/04/… Good news, spring framework 4.3 has provided a way to support your need, by adding sync=true in @Cacheable. here > docs.spring.io/spring-framework/docs/current/… also says your cache provider must support synchronized cache implementation...
While in most cases one cache is enough, the Spring framework also supports multiple caches to be passed as parameters: @Cacheable ( {"addresses", "directory"}) public String getAddress(Customer customer) {...} In this case, if any of the caches contain the required result, the result is returned and the method is not invoked.
Spring Framework has built-in classes and annotations to help developers dealing with caching. The @Cacheable annotation is one of them, it is the most widely used Spring cache-related annotations. In this article, we will go on the usage of this annotation and important keynotes about it.
If we use Spring Boot, then we can utilize the spring-boot-starter-cache starter package to easily add the caching dependencies: Under the hood, the starter brings the spring-context-support module. 3. Enable Caching To enable caching, Spring makes good use of annotations, much like enabling any other configuration level feature in the framework.
Good news, spring framework 4.3 has provided a way to support your need, by adding sync=true in @Cacheable.
When you use the @Cacheable annotation, the code that implements the cache search is outside of your method. Therefore, the synchronized modifier does not affect it.
If you want all the threads to use the cached result, you should create a synchronized method that wraps the invocation to the cacheable getNextPlaying method. Something like this:
public synchronized List<Match> getNextPlayingSynchronized(Date startingFrom, Locale locale){
return getNextPlaying(Date startingFrom, Locale locale);
}
...
@Cacheable(value="nextPlaying", key = "#startingFrom.getYear() + #startingFrom.getMonth() + #startingFrom.getDay() + #startingFrom.getHours() + #startingFrom.getMinutes() + #locale.getLanguage()")
public List<Match> getNextPlaying(Date startingFrom, Locale locale){
...//your old method without the synchronized modifier
}
It's important that these methods are in different classes. Otherwise, the aspects don't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With