Cache is a
map kind of data structure, where it stores the data in the form of <key,
value> pairs.
In this
post, I am going to show you how to create custom key generator and use it
while storing the data.
Step 1:
Define a key generator.
@Component("myEmployeeKeyGenerator")
public class EmployeeKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
if (target != null) {
sb.append(target.getClass().getSimpleName()).append("-");
}
if (method != null) {
sb.append(method.getName());
}
if (params != null) {
for (Object param : params) {
sb.append("-").append(param.getClass().getSimpleName()).append(":").append(param);
}
}
return sb.toString();
}
}
Step 2: Define a cache that is used to store the employee information.
@Configuration
@EnableCaching
public class AppConfig {
@Bean
public CacheManager cacheManager() {
List<ConcurrentMapCache> caches = Arrays.asList(new ConcurrentMapCache("myEmployeeCache"));
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches);
return cacheManager;
}
}
‘myEmployeeCache’
is the concurrent map cache.
@EnableCaching
enables Spring's annotation-driven cache management capability
Step 3:
You can use the cache
key generator ‘myEmployeeKeyGenerator ‘ and cache ‘myEmployeeCache’ to store
the information.
@Service
@CacheConfig(cacheNames = "myEmployeeCache", keyGenerator = "myEmployeeKeyGenerator")
public class EmployeeService {
@Cacheable
public Employee getEmployeeById(int id) {
System.out.println("getEmployeeById() is called");
for (Employee emp : emps) {
if (id == emp.getId()) {
return emp;
}
}
return null;
}
....
....
}
@CacheConfig(cacheNames
= "myEmployeeCache", keyGenerator =
"myEmployeeKeyGenerator")
It
provides a mechanism for sharing common cache-related settings at the class
level. All the @Cacheable method results of the service class are stored in ‘myEmployeeCache’
using the key generator ‘myEmployeeKeyGenerator’.
When you
call the method ‘getEmployeeById’, if the result is already available in cache,
then it is returned from cache, else actual method gets executed and result is
stored into cache.
Find the
below working application.
package com.sample.app.model;
public class Employee {
private int id;
private String firstName;
private String lastName;
public Employee(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
}
}
EmployeeKeyGenerator.java
package com.sample.app.generator;
import java.lang.reflect.Method;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;
@Component("myEmployeeKeyGenerator")
public class EmployeeKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
if (target != null) {
sb.append(target.getClass().getSimpleName()).append("-");
}
if (method != null) {
sb.append(method.getName());
}
if (params != null) {
for (Object param : params) {
sb.append("-").append(param.getClass().getSimpleName()).append(":").append(param);
}
}
return sb.toString();
}
}
EmployeeService.java
package com.sample.app.service;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.sample.app.model.Employee;
import java.util.*;
@Service
@CacheConfig(cacheNames = "myEmployeeCache", keyGenerator = "myEmployeeKeyGenerator")
public class EmployeeService {
private static List<Employee> emps = new ArrayList<>();
static {
emps.add(new Employee(1, "Ram", "Kota"));
emps.add(new Employee(2, "Raj", "Majety"));
emps.add(new Employee(3, "PTR", "Navakotla"));
emps.add(new Employee(4, "Krishna", "Boppana"));
}
@Cacheable
public Employee getEmployeeById(int id) {
System.out.println("getEmployeeById() is called");
for (Employee emp : emps) {
if (id == emp.getId()) {
return emp;
}
}
return null;
}
@Cacheable
public Employee getEmployeeByFirstName(String name) {
System.out.println("getEmployeeByFirstName() invoked");
for (Employee emp : emps) {
if (name.equals(emp.getFirstName())) {
return emp;
}
}
return null;
}
}
AppConfig.java
package com.sample.app.config;
import java.util.Arrays;
import java.util.List;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class AppConfig {
@Bean
public CacheManager cacheManager() {
List<ConcurrentMapCache> caches = Arrays.asList(new ConcurrentMapCache("myEmployeeCache"));
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches);
return cacheManager;
}
}
App.java
package com.sample.app;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import com.sample.app.model.Employee;
import com.sample.app.service.EmployeeService;
@SpringBootApplication
public class App {
@Autowired
private EmployeeService empService;
@Autowired
private CacheManager cacheManager;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
public CommandLineRunner demo() {
return (args) -> {
printNativeCache();
Employee emp = empService.getEmployeeById(1);
System.out.println(emp);
emp = empService.getEmployeeByFirstName("Krishna");
System.out.println(emp);
printNativeCache();
emp = empService.getEmployeeById(1);
System.out.println(emp);
emp = empService.getEmployeeByFirstName("Krishna");
System.out.println(emp);
emp = empService.getEmployeeById(1);
System.out.println(emp);
emp = empService.getEmployeeByFirstName("Krishna");
System.out.println(emp);
};
}
public void printNativeCache() {
System.out.println("\n**************************************");
Cache cache = cacheManager.getCache("myEmployeeCache");
System.out.println("-- native cache --");
Map<String, Object> map = (Map<String, Object>) cache.getNativeCache();
map.forEach((key, value) -> {
System.out.println(key + " = " + value);
});
System.out.println("**************************************\n");
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample.app</groupId>
<artifactId>springCache</artifactId>
<version>1</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
Total
project structure looks like below.
Run
App.java, you can see below messages in console.
************************************** -- native cache -- ************************************** getEmployeeById() is called Employee [id=1, firstName=Ram, lastName=Kota] getEmployeeByFirstName() invoked Employee [id=4, firstName=Krishna, lastName=Boppana] ************************************** -- native cache -- EmployeeService-getEmployeeByFirstName-String:Krishna = Employee [id=4, firstName=Krishna, lastName=Boppana] EmployeeService-getEmployeeById-Integer:1 = Employee [id=1, firstName=Ram, lastName=Kota] ************************************** Employee [id=1, firstName=Ram, lastName=Kota] Employee [id=4, firstName=Krishna, lastName=Boppana] Employee [id=1, firstName=Ram, lastName=Kota]
You can
download complete working application from this link.
No comments:
Post a Comment