Reputation: 322
Essentially, I have a few applications that will interact with the data layer independently. For each instance that is running, caching needs will likely be different. I know you can easily define different cacheManagers as an @Bean within its own class, such as:
@Bean
public CaffeineCache cacheA() {
return new CaffeineCache("CACHE_A",
Caffeine.newBuilder()
.expireAfterAccess(1, TimeUnit.DAYS)
.build());
}
@Bean
public CaffeineCache cacheB() {
return new CaffeineCache("CACHE_B",
Caffeine.newBuilder()
.expireAfterWrite(7, TimeUnit.DAYS)
.recordStats()
.build());
}
however, we're not necessarily wanting the code to recompile each time; therefore, it would be great if we could configure this as the application.properties level, as this is how the applications will interact.
I know with caffeine you can define some caches like so:
spring.cache.type=caffeine
spring.cache.cache-names=cache-a,cache-b
spring.cache.caffeine.spec=maximumSize=100, expireAfterWrite=1d
But to my understanding, the specs will be applied to every cache. My question is how do I apply different specs to each individual cache name at the application.properties level?
Thanks.
Upvotes: 2
Views: 3179
Reputation: 7871
I built a type-safe way. Sadly, Caffeine
and CaffeineSpec
are final and doesn't offer an empty public constructor. So I made a wrapper-class, which can be converted to Caffeine<Object, Object>
.
Here is the config-part:
@Data
@EnableCaching
@Configuration
@ConfigurationProperties(prefix = "caching")
public class CachingConfig {
private Map<String, CaffeineSpecWrapper> caches;
@Bean
public CacheManager cacheManager() {
var simpleCacheManager = new SimpleCacheManager();
var resultingCaches = new HashSet<Cache>();
caches
.forEach((cacheName, cacheProperties) -> resultingCaches.add(
new CaffeineCache(cacheName, Caffeine.newBuilder()
.expireAfterWrite(cacheProperties.getExpireAfterWrite())
.maximumSize(cacheProperties.getMaximumSize())
.build()))
);
simpleCacheManager.setCaches(resultingCaches);
return simpleCacheManager;
}
@Data
public static class CaffeineSpecWrapper {
private long maximumSize;
private Duration expireAfterWrite;
}
}
And with that, you will get the full spring-configuration-features. Down side: You have to define each caffeine-setting again.
Upvotes: 2
Reputation: 310
You can add a Map to the application.properties file and have different values per cache.The key in the map can be cache Name and the value can be combination of multiple comma separated values.
Example - cacheA:'100,1d' entry -> cacheA has maxSize=100 and expireAfterWrite=1d.
spring.caches={CACHE-A:'100,1d', \
CACHE-B:'200,7d', \
CACHE-C:'300,8d',\
CACHE-D:'400,9d',\
CACHE-E:'500,10d'}
In order to use it in your file:
private static final int MAX_SIZE_INDEX = 0;
private static final int EXPIRE_AFTER_DAYS_INDEX = 1;
@Value("$(spring.cache)")
private Map<String,String> cacheDefinitions;
@Bean
public CaffeineCache cacheA() {
String cacheName = "CACHE-A";
String[] properties = cacheDefinitions.get(cacheName).split(",");
return new CaffeineCache(cacheName,
Caffeine.newBuilder()
.expireAfterAccess(properties[EXPIRE_AFTER_DAYS_INDEX], TimeUnit.DAYS)
.maximumSize(properties[MAX_SIZE_INDEX])
.build());
}
@Bean
public CaffeineCache cacheB() {
String cacheName = "CACHE-B";
String[] properties = cacheDefinitions.get(cacheName).split(",");
return new CaffeineCache(cacheName,
Caffeine.newBuilder()
.expireAfterAccess(properties[EXPIRE_AFTER_DAYS_INDEX], TimeUnit.DAYS)
.maximumSize(properties[MAX_SIZE_INDEX])
.build());
}
A for loop on above map also works .
Upvotes: 0