Creating custom cache key using KeyGenerator interface

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

  1. target –> refers to the object which has the “@Cacheable”, “@CachePut” etc annotated method
  2. method –> refers to the actual method that is annotated with “@Cacheable”, “@CachePut” etc annotation.
  3. 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;
@Component
public 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 started
The key is addNumbersWithParam_100
Calculating addNumbersWithParam
5051
First time addNumbersWithParam(1, 100) call finished
-------------------------------------
Second time addNumbersWithParam(1, 100) call started
The key is addNumbersWithParam_100
5051
Second time addNumbersWithParam(1, 100) call finished
-------------------------------------
First time addNumbersWithParam(1, 1000) call started
The key is addNumbersWithParam_1000
Calculating addNumbersWithParam
500501
First time addNumbersWithParam(1, 1000) call finished
-------------------------------------
Second time addNumbersWithParam(1, 1000) call started
The key is addNumbersWithParam_1000
500501
Second time addNumbersWithParam(1, 1000) call finished
-------------------------------------

Leave a Reply