I have implemented caffeine cache in my application. I am caching data from few static tables. But i want to know if i can refresh / clear / reload cache manually or on demand using a REST API or any other way. Can any one please suggest a way to implement such a requirement.
I want something like :- an endpoint url like :- http://localhost:8080/refreshCache
this will trigger some method internally and clear the cache or reload new values in cache manually.
Below is the cache configuration:
@Configuration
public class CacheConfig{
private com.github.benmanes.caffeine.cache.Cache<Object, Object> cache;
@Bean
Caffeine<Object,Object> cacheBuilder(){
return Caffeine.newBuilder()
.initialCapacity(300)
.maximumSize(50000)
.expireAfterAccess(1, TimeUnit.DAYS)
.removalListener(new CacheRemovalListener())
.recordStats();
}
class CacheRemovalListener implements RemovalListener<Object, Object> {
@Override
public void onRemoval(Object key, Object value, RemovalCause cause) {
System.out.format("Removal listener called with key [%s], cause[%s], evicted [%s] %n",
key , cause.toString(), cause.wasEvicted());
}
}
}
You can use Spring's CacheManager to create CaffeineCache instances and then you can perform CRUD operations on any cache using CacheManager.
See Below code.
Bean Configuration:
public class CacheBeansConfig {
@Bean
public CacheManager cacheManager() {
// create multiple instances of cache
CaffeineCacheManager cacheManager = new CaffeineCacheManager("UserCache","InventoryCache");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
private Caffeine<Object, Object> caffeineCacheBuilder() {
return Caffeine.newBuilder()
.initialCapacity(<initial capacity>)
.maximumSize(<max size>)
.expireAfterAccess(<expire after hrs>, TimeUnit.HOURS)
.recordStats();
}
This will initialize your CacheManager with two Caffeeine Cache instances.
Use below Rest Controller Class to access these class.
@RestController
@RequestMapping(path = "/v1/admin/cache")
public class ACSCacheAdminController {
@Autowired
private CacheManager cacheManager;
/**
* call this to invalidate all cache instances
*/
@DeleteMapping(
path = "/",
produces = {"application/json"})
public void invalidateAll() {
Collection<String> cacheNames = cacheManager.getCacheNames();
cacheNames.forEach(this::getCacheAndClear);
}
/**
* call this to invalidate a given cache name
*/
@DeleteMapping(
path = "/{cacheName}",
produces = {"application/json"})
public void invalidateCache(@PathVariable("cacheName") final String cacheName) {
getCacheAndClear(cacheName);
}
/**
* Use this to refresh a cache instance
*/
@PostMapping(
path = "/{cacheName}",
produces = {"application/json"})
public void invalidateCache(@PathVariable("cacheName") final String cacheName) {
getCacheAndClear(cacheName);
Cache cache = cacheManager.getCache(cacheName);
// your logic to put in above cache instance
// use cache.put(key,value)
}
/**
* call this to invalidate cache entry by given cache name and cache key
*/
@DeleteMapping(
path = "/{cacheName}/{key}/",
produces = {"application/json"})
public void invalidateCacheKey(
@PathVariable("cacheName") final String cacheName, @PathVariable("key") Object key) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name for key invalidation: " + cacheName);
}
cache.evict(key);
}
@GetMapping(
path = "/{cacheName}/{key}",
produces = {"application/json"})
public ResponseEntity<Object> getByCacheNameAndKey(
@PathVariable("cacheName") final String cacheName, @PathVariable("key") final int key) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name: " + cacheName);
}
return ResponseEntity.ok().body(cache.get(key));
}
private void getCacheAndClear(final String cacheName) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name: " + cacheName);
}
cache.clear();
}
Just change the code as per your need :)