flexible caffeine cache manager

master
bvn13 2022-08-11 12:45:24 +03:00
parent d2f3e3c683
commit 30d08e49d0
4 changed files with 107 additions and 1 deletions

1
.gitignore vendored
View File

@ -26,3 +26,4 @@ hs_err_pid*
*~
\#*\#
\.\#
/.project

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -1,4 +1,9 @@
# Java Lessons
1) [Lesson #1](springboot2-junit5-skiptest/README.md) - How to write an annotation for your JUnit5 tests and to use application.properties from Spring environment
2) [Lesson #2](springboot2-request-logger/README.md) - How to log every request in Spring/SpringBoot web application
2) [Lesson #2](springboot2-request-logger/README.md) - How to log every request in Spring/SpringBoot web application
# Snippets
1) [Flexible Caffeine Cache Manager](flexible-caffeine-cache/FlexibleCaffeineCacheManager.java) - How to separate different cache configurations into one application using Caffeine cache

View File

@ -0,0 +1,98 @@
package com.pf.core.cache;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.util.StringUtils;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** Flexible Caffeine cache manager
* Idea: {@see "https://dzone.com/articles/multiple-cache-configurations-with-caffeine-and-sp"}
*
* to be used in cases when you need different settings per cache name
*
*/
@Slf4j
@ConfigurationProperties(prefix = "cache")
public class FlexibleCaffeineCacheManager extends CaffeineCacheManager implements InitializingBean {
/**
* default <code>spring.cache.cache-names</code> settings
* will be overridden with {@link FlexibleCaffeineCacheManager#specs}
*/
@Value("${spring.cache.cache-names:}")
private String springCacheNames;
/**
* default <code>spring.cache.caffeine.spec</code> settings
* will be overridden with {@link FlexibleCaffeineCacheManager#specs}
*/
@Value("${spring.cache.caffeine.spec:}")
private String springCacheSpecs;
/**
* This field could be populated from <code>application.(yaml|properties)</code> file
* All features are listed into {@link CaffeineSpec}
*/
@Getter @Setter
private Map<String, String> specs = new ConcurrentHashMap<>();
@Getter
private Map<String, Caffeine<Object, Object>> builders = new ConcurrentHashMap<>();
private CacheLoader<Object, Object> cacheLoader;
@Override
public void setCacheLoader(@Nonnull CacheLoader<Object, Object> cacheLoader) {
this.cacheLoader = cacheLoader;
}
/**
* reads all standard settings from application.(properties|yml) and adjust proper cache builders
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
if (StringUtils.hasText(springCacheNames) && !springCacheNames.equals("${spring.cache.cache-names:}")) {
String[] cacheNames = springCacheNames.split(",");
if (cacheNames.length > 0) {
for (String cacheName : cacheNames) {
if (StringUtils.hasText(cacheName)) {
if (!specs.containsKey(cacheName.trim())) {
specs.put(cacheName.trim(), springCacheSpecs);
}
}
}
}
}
for (Map.Entry<String, String> cacheSpecEntry : specs.entrySet()) {
log.info("Creating cache with name {} and specs: {}", cacheSpecEntry.getKey(), cacheSpecEntry.getValue());
builders.put(cacheSpecEntry.getKey(), Caffeine.from(cacheSpecEntry.getValue()));
}
}
@Nonnull
@Override
protected Cache<Object, Object> createNativeCaffeineCache(String name) {
Caffeine<Object, Object> builder = builders.get(name);
if (builder == null) {
return super.createNativeCaffeineCache(name);
}
if (this.cacheLoader != null) {
return builder.build(this.cacheLoader);
} else {
return builder.build();
}
}
}