Caffeine cache is a high-performance caching library for Java. In this post, I am going to explain how to integrate caffeine cache in spring boot application.
Step 1: Define cache key generator.
@Component("myCacheKeyGenerator")
public class CacheKeyGenerator 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 cache config class by extending CachingConfigurerSupport class.
CacheConfig.java
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Bean
@Override
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("myOrgCache", "myEmployeeCache");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
Caffeine caffeineCacheBuilder() {
return Caffeine.newBuilder().initialCapacity(100).maximumSize(500).expireAfterWrite(10, TimeUnit.SECONDS)
.recordStats();
}
@Override
public KeyGenerator keyGenerator() {
return new CacheKeyGenerator();
}
}
Step 3: Use this cache on the methods that you are intrested to cache the result.
@Service
@CacheConfig(cacheNames = "myEmployeeCache")
public class EmployeeService {
private static List<Employee> emps = new ArrayList<>();
@Cacheable
public Employee getEmployeeById(int id) {
// System.out.println("getEmployeeById() is called");
for (Employee emp : emps) {
if (id == emp.getId()) {
return emp;
}
}
return null;
}
}
Find the below working application.
Step 1: Create new maven project ‘caffeine-hello-world’.
Step 2: Update pom.xml with maven dependencies.
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>caffeine-hello-world</artifactId>
<version>1</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
</project>
Step 3: Define model classes.
Organization.java
package com.sample.app.model;
public class Organization {
private int id;
private String name;
private String description;
public Organization(int id, String name, String description) {
super();
this.id = id;
this.name = name;
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Organization [id=" + id + ", name=" + name + ", description=" + description + "]";
}
}
Employee.java
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 + "]";
}
}
Step 4: Define service classes.
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")
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;
}
}
OrganizaitonService.java
package com.sample.app.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.sample.app.model.Organization;
@Service
@CacheConfig(cacheNames = "myOrgCache")
public class OrganizationService {
private static final List<Organization> orgs = new ArrayList<>();
static {
Organization org1 = new Organization(1, "ABC Corp", "Hello ABC Corp");
Organization org2 = new Organization(2, "DEF Corp", "Hello DEF Corp");
Organization org3 = new Organization(3, "GHI Corp", "Hello GHI Corp");
Organization org4 = new Organization(4, "JKL Corp", "Hello JKL Corp");
Organization org5 = new Organization(5, "MNO Corp", "Hello MNO Corp");
orgs.add(org1);
orgs.add(org2);
orgs.add(org3);
orgs.add(org4);
orgs.add(org5);
}
@Cacheable
public Organization getById(int id) {
// System.out.println("getById() called");
for (Organization org : orgs) {
if (id == org.getId()) {
return org;
}
}
return null;
}
@Cacheable
public Organization getByName(String name) {
// System.out.println("getByName() called");
for (Organization org : orgs) {
if (org.getName().equals(name)) {
return org;
}
}
return null;
}
}
Step 5: Define Cache ket generator.
CacheKeyGenerator.java
package com.sample.app.generator;
import java.lang.reflect.Method;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;
@Component("myCacheKeyGenerator")
public class CacheKeyGenerator 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 6: Define CacheConfig class.
CacheConfig.java
package com.sample.app.config;
import java.util.concurrent.TimeUnit;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.sample.app.generator.CacheKeyGenerator;
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Bean
@Override
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("myOrgCache", "myEmployeeCache");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
Caffeine caffeineCacheBuilder() {
return Caffeine.newBuilder().initialCapacity(100).maximumSize(500).expireAfterWrite(10, TimeUnit.SECONDS)
.recordStats();
}
@Override
public KeyGenerator keyGenerator() {
return new CacheKeyGenerator();
}
}
Step 7: Define main application class.
App.java
package com.sample.app;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
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.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.context.annotation.Bean;
import com.sample.app.model.Employee;
import com.sample.app.model.Organization;
import com.sample.app.service.EmployeeService;
import com.sample.app.service.OrganizationService;
@SpringBootApplication
public class App {
@Autowired
private EmployeeService empService;
@Autowired
private OrganizationService orgService;
@Autowired
private CacheManager cacheManager;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
public void getEmployeeAndOrgDetails() {
Employee emp = empService.getEmployeeById(1);
// System.out.println(emp);
emp = empService.getEmployeeByFirstName("Krishna");
// System.out.println(emp);
Organization org = orgService.getById(3);
// System.out.println(org);
org = orgService.getByName("GHI Corp");
// System.out.println(org);
}
@Bean
public CommandLineRunner demo() {
return (args) -> {
printNativeCache();
getEmployeeAndOrgDetails();
printNativeCache();
// getEmployeeAndOrgDetails();
System.out.println("\nSleeping for 5 seconds");
TimeUnit.SECONDS.sleep(5);
printNativeCache();
System.out.println("\nSleeping for 5 seconds");
TimeUnit.SECONDS.sleep(5);
printNativeCache();
};
}
public void printNativeCache() {
System.out.println("\n**************************************");
System.out.println("-- native cache --");
Collection<String> cacheNames = cacheManager.getCacheNames();
for (String cacheName : cacheNames) {
System.out.println("\nFor the cache : " + cacheName);
CaffeineCache cache = (CaffeineCache) cacheManager.getCache(cacheName);
com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache = cache.getNativeCache();
Map<Object, Object> map = nativeCache.asMap();
for (Object key : map.keySet()) {
System.out.println(key + " -> " + map.get(key));
}
}
System.out.println("**************************************\n");
}
}
Total project structure looks like below.
Run App.java, you will see below messages in console.
************************************** -- native cache -- For the cache : myOrgCache For the cache : myEmployeeCache ************************************** ************************************** -- native cache -- For the cache : myOrgCache OrganizationService-getById-Integer:3 -> Organization [id=3, name=GHI Corp, description=Hello GHI Corp] OrganizationService-getByName-String:GHI Corp -> Organization [id=3, name=GHI Corp, description=Hello GHI Corp] For the cache : myEmployeeCache EmployeeService-getEmployeeByFirstName-String:Krishna -> Employee [id=4, firstName=Krishna, lastName=Boppana] EmployeeService-getEmployeeById-Integer:1 -> Employee [id=1, firstName=Ram, lastName=Kota] ************************************** Sleeping for 5 seconds ************************************** -- native cache -- For the cache : myOrgCache OrganizationService-getById-Integer:3 -> Organization [id=3, name=GHI Corp, description=Hello GHI Corp] OrganizationService-getByName-String:GHI Corp -> Organization [id=3, name=GHI Corp, description=Hello GHI Corp] For the cache : myEmployeeCache EmployeeService-getEmployeeByFirstName-String:Krishna -> Employee [id=4, firstName=Krishna, lastName=Boppana] EmployeeService-getEmployeeById-Integer:1 -> Employee [id=1, firstName=Ram, lastName=Kota] ************************************** Sleeping for 5 seconds ************************************** -- native cache -- For the cache : myOrgCache For the cache : myEmployeeCache **************************************
You can download complete working application from below link.
https://github.com/harikrishna553/springboot/tree/master/cache/caffeine-hello-world
No comments:
Post a Comment