In this post under Spring Caching, I will show with example how to create custom cache key from method name using SpEL.
In SpEL, to access SpEL context object we will use “#root” variable.
This SpEL context object will have below information
- reference to target method that is annotated with @Cacheable, @CachePut, or @CacheEvict
- reference to target object containing the annotated method
- reference to Class object of the target object
- annotated target method name
- annotated target method arguments
- collection of caches used by target method
We can use these information to create our own custom key in SpEL.
Here in this post, I will show how to access method name in SpEL to create our own custom cache key.
For our example we will use the below “Calculator” class
Calculator
package caching.package6;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component;@Componentpublic class Calculator { @Cacheable(cacheNames = "addNumbersWithParam_region", key = "#root.methodName + '_' + (#root.args[0] * #root.args[1])") public int addNumbersWithParam(int start, int end) { System.out.println("Calculating addNumbersWithParam"); int result = 1; for(int i = start; i <= end; i++) { result = result + i; } return result; }}
In the above code, at line 8, I have used “@Cacheable” annotation for the method “addNumbersWithParam”.
The cache region name I have given is “addNumbersWithParam_region”
The SpEL that I have used to generate custom key is “#root.methodName + ‘_’ + (#root.args[0] * #root.args[1])” and assigned it to “key” attribute of “@Cacheable” annotation.
I have used the “methodName” property of “#root” object to access the method name.
At runtime if I call the method with arguments “start = 5” and “end = 100”, the key will be “addNumbersWithParam_500”, and the value will be sum of all numbers from 5 to 100.
Next time when I call the method with same arguments, the value is retrieved from the cache using the key “addNumbersWithParam_500” instead of executing the method again.
Below is the main class for your reference.
Main class
package caching.package6;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.EnableCaching;import org.springframework.cache.concurrent.ConcurrentMapCacheManager;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@EnableCaching@Configuration@ComponentScan(basePackages = "caching.package6")public class Example6 { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Example6.class); Calculator calculator = annotationConfigApplicationContext.getBean(Calculator.class); System.out.println("First time addNumbersWithParam(1, 100) call started"); System.out.println(calculator.addNumbersWithParam(1, 100)); System.out.println("First time addNumbersWithParam(1, 100) call finished"); System.out.println("-------------------------------------"); System.out.println("Second time addNumbersWithParam(1, 100) call started"); System.out.println(calculator.addNumbersWithParam(1, 100)); System.out.println("Second time addNumbersWithParam(1, 100) call finished"); System.out.println("-------------------------------------"); }}
Below is the output
Output
First time addNumbersWithParam(1, 100) call startedCalculating addNumbersWithParam5051First time addNumbersWithParam(1, 100) call finished-------------------------------------Second time addNumbersWithParam(1, 100) call started5051Second time addNumbersWithParam(1, 100) call finished-------------------------------------