Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set a different specification per cache using caffeine in spring boot?

I have a simple sprint boot application using spring boot 1.5.11.RELEASE with @EnableCaching on the Application Configuration class.

pom.xml

 <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>

application.properties

spring.cache.type=caffeine
spring.cache.cache-names=cache-a,cache-b
spring.cache.caffeine.spec=maximumSize=100, expireAfterWrite=1d

Question

My question is simple, how can one specify a different size/expiration per cache. E.g. perhaps it's acceptable for cache-a to be valid for 1 day. But cache-b might be ok for 1 week. The specification on a caffeine cache appears to be global to the CacheManager rather than Cache. Am I missing something? Perhaps there is a more suitable provider for my use case?

like image 837
David Avatar asked Apr 17 '18 18:04

David


People also ask

What is maximum size in caffeine cache?

Caffeine Cache Configuration The Caffeine spec define the cache maximum size as 500 and a time to live of 10 minutes.

Is caffeine cache distributed?

Similar to Ehcache, Caffeine cannot work as a distributed cache.

How do you use caffeine cache in spring boot?

The primary way to use caching in Spring Boot is with the @Cacheable annotation. This annotation works on any method of a Spring bean (or even the entire class). It instructs the registered cache manager to store the result of the method call in a cache.


4 Answers

This is your only chance:

@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()); } 

Just expose your custom caches as beans. They are automatically added to the CaffeineCacheManager.

like image 52
membersound Avatar answered Sep 19 '22 05:09

membersound


I config multiple cache manager like this

    @Bean     public CacheManager template() {         CaffeineCacheManager cacheManager = new CaffeineCacheManager(CACHE_TEMPLATE);         cacheManager.setCaffeine(caffeineCacheBuilder(this.settings.getCacheExpiredInMinutes()));         return cacheManager;     }      @Bean     public CacheManager daily() {         CaffeineCacheManager cacheManager = new CaffeineCacheManager(CACHE_TEMPLATE);         cacheManager.setCaffeine(caffeineCacheBuilder(24 * 60));         return cacheManager;     } 

And use the cache normally

    @Cacheable(cacheManager = "template")     @Override     public ArrayList<FmdModel> getData(String arg) {         return ....;     } 

Update

It look like the above code has a big mistake. So I change to

@Configuration @Data @Slf4j @ConfigurationProperties(prefix = "caching") public class AppCacheConfig {       //This cache spec is load from `application.yml` file     // @ConfigurationProperties(prefix = "caching")     private Map<String, CacheSpec> specs;      @Bean     public CacheManager cacheManager(Ticker ticker) {         SimpleCacheManager manager = new SimpleCacheManager();         if (specs != null) {             List<CaffeineCache> caches = specs.entrySet().stream()                     .map(entry -> buildCache(entry.getKey(), entry.getValue(), ticker)).collect(Collectors.toList());             manager.setCaches(caches);         }         return manager;     }      private CaffeineCache buildCache(String name, CacheSpec cacheSpec, Ticker ticker) {         log.info("Cache {} specified timeout of {} min, max of {}", name, cacheSpec.getTimeout(), cacheSpec.getMax());         final Caffeine<Object, Object> caffeineBuilder = Caffeine.newBuilder()                 .expireAfterWrite(cacheSpec.getTimeout(), TimeUnit.MINUTES).maximumSize(cacheSpec.getMax())                 .ticker(ticker);         return new CaffeineCache(name, caffeineBuilder.build());     }      @Bean     public Ticker ticker() {         return Ticker.systemTicker();     } }  

This AppCacheConfig class allow you to define many cache spec as you prefer. And you can define cache spec in application.yml file

caching:   specs:     template:       timeout: 10 #15 minutes       max: 10_000     daily:       timeout: 1440 #1 day       max: 10_000     weekly:       timeout: 10080 #7 days       max: 10_000     ...:       timeout: ... #in minutes       max:  

But still, this class has a limitation that we can only set timeout and max size only. because of CacheSpec class

@Data public class CacheSpec {      private Integer timeout;     private Integer max = 200;  } 

Therefore, If you like to add more config parameters, you are to add more parameters on CacheSpec class and set the Cache configuration on AppCacheConfig.buildCache function.
Hope this help!

like image 23
nokieng Avatar answered Sep 18 '22 05:09

nokieng


I converted my initial PR into a separate tiny project.

To start using it just add the latest dependency from Maven Central:

<dependency>
    <groupId>io.github.stepio.coffee-boots</groupId>
    <artifactId>coffee-boots</artifactId>
    <version>2.0.0</version>
</dependency>

Format of properties is the following:

coffee-boots.cache.spec.myCache=maximumSize=100000,expireAfterWrite=1m

If no specific configuration is defined, CacheManager defaults to Spring's behavior.

like image 25
stepio Avatar answered Sep 19 '22 05:09

stepio


Instead of using SimpleCacheManager, you can use registerCustomCache() method of CaffeineCacheManager. Below is an example:

CaffeineCacheManager manager = new CaffeineCacheManager();
manager.registerCustomCache("Cache1",Caffeine.newBuilder().maximumSize(1000).expireAfterAccess(6, TimeUnit.MINUTES).build());

manager.registerCustomCache("Cache2",Caffeine.newBuilder().maximumSize(2000).expireAfterAccess(12, TimeUnit.MINUTES).build());
like image 41
ayman.mostafa Avatar answered Sep 19 '22 05:09

ayman.mostafa