In this post, I am going to explain how to get the cache events by implementing CacheEventListener.
Supported event types
org.ehcache.event.EventType enum define below event types.
a. EVICTED : Represents a cache entry being evicted
b. EXPIRED : Represents a cache entry being expired
c. REMOVED : Represents a cache entry being removed
d. CREATED : Represents a cache entry being created
e. UPDATED : Represents a cache entry being updated
Supported event firing modes
org.ehcache.event.EventFiring enum defines below event firing modes.
a. ASYNCHRONOUS: Events will fire asynchronously. The mutating thread does not have to wait for firing to complete.
b. SYNCHRONOUS: Events will fire synchronously. The mutating thread will wait for firing to complete.
Supported event ordering modes
org.ehcache.event.EventOrdering define below event ordering modes.
a. UNORDERED: Events may be observed out of order.
b. ORDERED: Ordering of events is guaranteed on a per-key basis.
Let’s define custom cache event listener by implementing CacheEventListener interface.
public class MyCacheEnventListener implements CacheEventListener<Object, Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyCacheEnventListener.class);
public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
LOGGER.info("\n-----------------------------------------------");
LOGGER.info("Event received");
LOGGER.info("event type: {}", cacheEvent.getType());
LOGGER.info("event key: {}", cacheEvent.getKey());
LOGGER.info("old value: {}", cacheEvent.getOldValue());
LOGGER.info("new value: {}", cacheEvent.getNewValue());
LOGGER.info("-----------------------------------------------");
}
}
Next configure this ‘MyCacheEnventListener’ in ehcache.xml file.
ehcache.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<cache alias="myEmployeeCache">
<key-type>java.lang.Object</key-type>
<value-type>java.lang.Object</value-type>
<expiry>
<ttl unit="seconds">10</ttl>
</expiry>
<listeners>
<listener>
<class>com.sample.app.listeners.MyCacheEnventListener</class>
<event-firing-mode>SYNCHRONOUS</event-firing-mode>
<event-ordering-mode>UNORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap unit="entries">2</heap>
<offheap unit="MB">10</offheap>
</resources>
</cache>
</config>
As you observe the definition of xml file, I set event-firing-mode to SYNCHRONOUS for the demo purpose, you can set this to 'ASYNCHRONOUS' in production.
Specify ehcache.xml file location in application.yml file.
spring:
cache:
jcache:
config: classpath:ehcache.xml
Follow below step-by-step procedure to build complete working application.
Step 1: Create new maven project ‘spring-cache-event-listener’.
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample.app</groupId>
<artifactId>spring-cache-event-listener</artifactId>
<version>1</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</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>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
</dependencies>
</project>
Step 3: Create ehcache.xml file under src/main/resources folder.
ehcache.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<cache alias="myEmployeeCache">
<key-type>java.lang.Object</key-type>
<value-type>java.lang.Object</value-type>
<expiry>
<ttl unit="seconds">10</ttl>
</expiry>
<listeners>
<listener>
<class>com.sample.app.listeners.MyCacheEnventListener</class>
<event-firing-mode>SYNCHRONOUS</event-firing-mode>
<event-ordering-mode>ORDERED</event-ordering-mode>
<events-to-fire-on>EVICTED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>REMOVED</events-to-fire-on>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>UPDATED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap unit="entries">2</heap>
<offheap unit="MB">10</offheap>
</resources>
</cache>
</config>
Step 4: Create application.yml file under src/main/resources folder.
application.yml
spring:
cache:
jcache:
config: classpath:ehcache.xml
Step 5: Create Employee model class.
Employee.java
package com.sample.app.model;
import java.io.Serializable;
public class Employee implements Serializable{
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 6: Define EmployeeService class.
EmployeeService.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.Employee;
@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(key = "{#id}")
public Employee getEmployeeById(int id) {
System.out.println("getEmployeeById: Getting the informaiton from internal list");
for (Employee emp : emps) {
if (id == emp.getId()) {
return emp;
}
}
return null;
}
@Cacheable(key = "{#name}")
public Employee getEmployeeByFirstName(String name) {
System.out.println("getEmployeeByFirstName: Getting the informaiton from internal list");
for (Employee emp : emps) {
if (name.equals(emp.getFirstName())) {
return emp;
}
}
return null;
}
}
Step 7: Define MyCacheEnventListener class.
MyCacheEnventListener.java
package com.sample.app.listeners;
import org.ehcache.event.CacheEvent;
import org.ehcache.event.CacheEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyCacheEnventListener implements CacheEventListener<Object, Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyCacheEnventListener.class);
public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
LOGGER.info("\n-----------------------------------------------");
LOGGER.info("Event received");
LOGGER.info("event type: {}", cacheEvent.getType());
LOGGER.info("event key: {}", cacheEvent.getKey());
LOGGER.info("old value: {}", cacheEvent.getOldValue());
LOGGER.info("new value: {}", cacheEvent.getNewValue());
LOGGER.info("-----------------------------------------------");
}
}
Step 8: Define CacheConfig class.
CacheConfig.java
package com.sample.app.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
}
Step 9: Define main application class.
App.java
package com.sample.app;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.context.annotation.Bean;
import com.sample.app.model.Employee;
import com.sample.app.service.EmployeeService;
@SpringBootApplication
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
@Autowired
private EmployeeService empService;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
public void getEmployeeDetails() {
System.out.println("\n");
LOGGER.info("\nGetting employee details with id 1");
Employee emp = empService.getEmployeeById(1);
LOGGER.info("emp : {}", emp);
System.out.println("\n");
LOGGER.info("Getting employee details with name 'Krishna'");
emp = empService.getEmployeeByFirstName("Krishna");
LOGGER.info("emp : {}", emp);
}
@Bean
public CommandLineRunner demo() {
return (args) -> {
getEmployeeDetails();
LOGGER.info("Sleeping for 4 seconds");
TimeUnit.SECONDS.sleep(4);
getEmployeeDetails();
LOGGER.info("Sleeping for 4 seconds");
TimeUnit.SECONDS.sleep(4);
getEmployeeDetails();
LOGGER.info("Sleeping for 4 seconds");
TimeUnit.SECONDS.sleep(4);
getEmployeeDetails();
};
}
}
Total project structure looks like below.
Run App.java, you will see below messages in console.
Getting employee details with id 1 getEmployeeById: Getting the informaiton from internal list 2022-06-30 16:15:17.063 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: CREATED 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [1] 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: null 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:17.064 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:17.065 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:17.065 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with name 'Krishna' getEmployeeByFirstName: Getting the informaiton from internal list 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: CREATED 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [Krishna] 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: null 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:17.066 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:17.066 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:17.067 INFO 82133 --- [ main] com.sample.app.App : Sleeping for 4 seconds 2022-06-30 16:15:21.069 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with id 1 2022-06-30 16:15:21.077 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:21.078 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with name 'Krishna' 2022-06-30 16:15:21.078 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:21.078 INFO 82133 --- [ main] com.sample.app.App : Sleeping for 4 seconds 2022-06-30 16:15:25.079 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with id 1 2022-06-30 16:15:25.080 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:25.080 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with name 'Krishna' 2022-06-30 16:15:25.080 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:25.080 INFO 82133 --- [ main] com.sample.app.App : Sleeping for 4 seconds 2022-06-30 16:15:29.082 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with id 1 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: EXPIRED 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [1] 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: null 2022-06-30 16:15:29.085 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- getEmployeeById: Getting the informaiton from internal list 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: CREATED 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [1] 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: null 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:29.087 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.087 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=1, firstName=Ram, lastName=Kota] 2022-06-30 16:15:29.087 INFO 82133 --- [ main] com.sample.app.App : Getting employee details with name 'Krishna' 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: EXPIRED 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [Krishna] 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: null 2022-06-30 16:15:29.088 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- getEmployeeByFirstName: Getting the informaiton from internal list 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : Event received 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event type: CREATED 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : event key: [Krishna] 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : old value: null 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : new value: Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:29.089 INFO 82133 --- [e [_default_]-0] c.s.app.listeners.MyCacheEnventListener : ----------------------------------------------- 2022-06-30 16:15:29.089 INFO 82133 --- [ main] com.sample.app.App : emp : Employee [id=4, firstName=Krishna, lastName=Boppana] 2022-06-30 16:15:59.100 INFO 82133 --- [ionShutdownHook] org.ehcache.core.EhcacheManager : Cache 'myEmployeeCache' removed from EhcacheManager.
You can download complete working application from this link.
No comments:
Post a Comment