Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend default Spring Boot CacheManager configuration

I'm using Spring Boot caching support in my web application and I set Caffeine as cache provider.

I have several caches in my project, most of them have common configuration, but for two specific caches I need to set different parameters.

In my application.properties I have something similar:

spring.cache.cache-names=a-cache,b-cache,c-cache, ...
spring.cache.caffeine.spec=maximumSize=200,expireAfterWrite=3600s

This for common caches. Then I'd like to extend this configuration with custom params.

This post explains how to configure caches via @Configuration class, but using this method I completely override the common configuration.

What I need is something like:

@Configuration
public class CacheConfiguration {

    @Autowired
    private CacheManager cacheManager;

    @Bean
    public CacheManager cacheManager(Ticker ticker) {
        CaffeineCache c1 = new CaffeineCache("my-custom-cache", Caffeine.newBuilder()
                       .expireAfterWrite(10, TimeUnit.MINUTES)
                       .maximumSize(400)
                       .build());

        // ...

        cacheManager.setCaches(Arrays.asList(..., c1, ... )); // here I'd like to add custom caches...
        return cacheManager;
    }

}

But declaring a new CacheManager bean, the "original" cacheManager is not autowired...

Is there a way to implement what I need?

like image 747
davioooh Avatar asked Oct 30 '22 08:10

davioooh


1 Answers

I utilized a CompositeCacheManager to handle that situation. Essentially I create my custom configured CaffeineCaches and put them in a SimpleCacheManager, then use a CaffeineCacheManager with my default settings. I put both the cache managers into the CompositeCacheManager and spring will look for a matching Cache in my SimpleCacheManager first, and if it is not found it will look in the CaffeineCacheManager. If the CaffeineCacheManager also does not have a match it will create a new cache with the default settings.

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

  private static final Logger logger = LoggerFactory.getLogger(CacheConfig.class);

  @Autowired
  private MyCacheProperties myCacheProperties;

  @Bean
  @Override
  public CacheManager cacheManager() {
    // create a custom configured cache for each of the customCacheSpecs in the myCacheProperties
    final List<CaffeineCache> customCaches = myCacheProperties.getCustomCacheSpecs().entrySet().stream()
        .map(entry -> buildCache(entry.getKey(), entry.getValue()))
        .collect(Collectors.toList());
    // put the custom caches in a SimpleCacheManager
    final SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
    simpleCacheManager.setCaches(customCaches);

    // create a Caffeine Cache manager based on the defaultCacheSpec in the myCacheProperties
    final CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
    caffeineCacheManager.setCacheSpecification(myCacheProperties.getDefaultCacheSpec());
    caffeineCacheManager.setAllowNullValues(false);

    // create a CompositeCacheManager which will first look for a customized cache from the simpleCacheManager and then
    // if no cache is found it will delegate to the caffeineCacheManager.  If the caffeineCacheManager already has
    // created an appropriate cache it will be used, other wise it will create a new cache with the default
    // settings
    final CompositeCacheManager compositeCacheManager = new CompositeCacheManager(simpleCacheManager,
        caffeineCacheManager);
    return compositeCacheManager;
  }

  private CaffeineCache buildCache(final String name, final String cacheSpec) {
    final CaffeineCache caffeineCache = new CaffeineCache(name, Caffeine.from(cacheSpec)
        .build());
    logger.debug("created custom cache: name='{}', and spec='{}'", name, cacheSpec);
    return caffeineCache;
  }
}

Thanks to https://medium.com/@d.lopez.j/configuring-multiple-ttl-caches-in-spring-boot-dinamically-75f4aa6809f3 for the inspiration

like image 138
MattJ Avatar answered Nov 02 '22 22:11

MattJ