In all my previous posts under Spring Caching, I have used Java primitive types and String as cache key.
In this post under Spring Caching, I will show with example how to create custom cache key.
To create a custom cache key we need to implement Spring interface “KeyGenerator” and provide the logic that creates custom key in its “generate” method.
For our example, I have created a class “CustomKeyGenerator” that implements “KeyGenerator” interface as shown below
CustomKeyGenerator
package caching.package12;import org.springframework.cache.interceptor.KeyGenerator;import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Component("customKeyGenerator")public class CustomKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { Integer start = (Integer) params[0]; Integer end = (Integer) params[1]; String key = method.getName() + "_" + (start * end); System.out.println("The key is " + key); return key; }}
As you see in the above code, the class “CustomKeyGenerator” implements “KeyGenerator” interface and provide implementation for “generate” method.
The “generate” method parameters are
- target –> refers to the object which has the “@Cacheable”, “@CachePut” etc annotated method
- method –> refers to the actual method that is annotated with “@Cacheable”, “@CachePut” etc annotation.
- params –> refers to parameters passed to “@Cacheable”, “@CachePut” etc annotated method.
So in my code, I am using parameters and method name to create a key and return it.
Next I will show how to use this class “CustomKeyGenerator”.
Below is the “Calculator” class using the class “CustomKeyGenerator”.
Calculator
package caching.package12;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component;@Componentpublic class Calculator { @Cacheable(cacheNames = "addNumbersWithParam_region", keyGenerator = "customKeyGenerator") 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; }}
As you can see in the above code, “@Cacheable” annotation is applied to the method “addNumbersWithParam”.
To this “@Cacheable” annotation, I have provided the cache name and also set the “keyGenerator” attribute to bean name of “CustomKeyGenerator” class.
As a result of which Spring framework will use “CustomKeyGenerator” class to generate keys for the entries that will be put in the cache.
In this way we can create custom cache key.
Below is the main class for your reference.
Main Class
package caching.package12;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.package12")public class Example12 { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Example12.class); Calculator calculator = context.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("-------------------------------------"); System.out.println("First time addNumbersWithParam(1, 1000) call started"); System.out.println(calculator.addNumbersWithParam(1, 1000)); System.out.println("First time addNumbersWithParam(1, 1000) call finished"); System.out.println("-------------------------------------"); System.out.println("Second time addNumbersWithParam(1, 1000) call started"); System.out.println(calculator.addNumbersWithParam(1, 1000)); System.out.println("Second time addNumbersWithParam(1, 1000) call finished"); System.out.println("-------------------------------------"); }}
Below is the output
Output
First time addNumbersWithParam(1, 100) call startedThe key is addNumbersWithParam_100Calculating addNumbersWithParam5051First time addNumbersWithParam(1, 100) call finished-------------------------------------Second time addNumbersWithParam(1, 100) call startedThe key is addNumbersWithParam_1005051Second time addNumbersWithParam(1, 100) call finished-------------------------------------First time addNumbersWithParam(1, 1000) call startedThe key is addNumbersWithParam_1000Calculating addNumbersWithParam500501First time addNumbersWithParam(1, 1000) call finished-------------------------------------Second time addNumbersWithParam(1, 1000) call startedThe key is addNumbersWithParam_1000500501Second time addNumbersWithParam(1, 1000) call finished-------------------------------------