Search code examples
spring-bootehcacheconfiguration-fileshazelcastjcache

Mixing declarative and imperative JCache configurations


I'm trying to setup (J)caches in a mix of declarative and imperative configuration, as the JCache standard doesn't provide a means to limit the max size a cache can occupy. I want to do it as much "provider independent" as possible, so I have the flexibility to change provider in the future. Currently I have the limitation of using Java 7, so Caffeine is discarded, I believe.

I keep a list of the caches and the duration (TTL) for their entries in my application.yaml, which I get with a property loader. I then create my caches with the code below:

@Bean
public List<Cache<Object, Object>> getCaches() {
    CacheManager cacheManager = this.getCacheManager();
    List<Cache<Object, Object>> caches = new ArrayList();
    Map<String, String> cacheconfigs = this.cacheConfigPropertyLoader.getPropertyLoader().getCacheconfigs();
    Set<String> keySet = cacheconfigs.keySet();
    Iterator i$ = keySet.iterator();

    while(i$.hasNext()) {
        String name = (String)i$.next();
        String durationMinutes = (String)cacheconfigs.get(name);
        caches.add((new GenericDefaultCacheConfigurator.GenericDefaultCacheConfig(name, new Duration(TimeUnit.MINUTES, Long.valueOf(durationMinutes)))).getCache(cacheManager));
    }

    return caches;
}

@Bean
public CacheManager getCacheManager() {
    return Caching.getCachingProvider().getCacheManager();
}

private class GenericDefaultCacheConfig {
    public GenericDefaultCacheConfig(String cacheName, Duration duration) {
         public GenericDefaultCacheConfig(String id, Duration duration, Factory expiryPolicyFactory) {
        CACHE_ID = id;
        DURATION = duration;
        EXPIRY_POLICY = expiryPolicyFactory;
    }
    private MutableConfiguration<Object, Object> getCacheConfiguration() {
        return new MutableConfiguration<Object, Object>()
                    .setTypes(Object.class, Object.class)
                    .setStoreByValue(true)
                    .setExpiryPolicyFactory(EXPIRY_POLICY);
    }
    public Cache<Object, Object> getCache(CacheManager cacheManager) {
        CacheManager cm = cacheManager;
        Cache<K, V> cache = cm.getCache(CACHE_ID, Object.class, Object.class);
        if (cache == null)
           cache = cm.createCache(CACHE_ID, getCacheConfiguration());
        return cache;
    }
}

That works fine for creating my caches and using it with annotations and imperative code, no matter which JCache provider I use in the POM (I tested it with org.jsr107.ri, hazelcast, and EhCache).

Now I need to limit the max size of all the caches with a proprietary configuration. I need a common/default configuration that would apply to any cache created by that provider, irrespective of their other particular characteristics (Expiry policy, time to live, etc.) which are set by the imperative configuration.

I've been having issues, when including a configuration file, for the cache manager configured with the config file to be used to create these caches declared in my yaml file. Any ideas/suggestions? I recall reading somewhere of using * in Ehcache configuration, but I could not find that page again.


Solution

  • I will put my findings here so they can be used as a reference.

    Hazelcast

    As mdogan replied, Hazelcast doesn't support this. It has the concept of configurations with wildcards (check this reply), but those don't apply to caches configured programmatically.

    Ehcache

    In Ehcache I found a way. As per their documentation:

    Configure a default template from which all programmatically created Cache instances inherit

    You need to declare a default-template as below:

    <config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
        xsi:schemaLocation="
            http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
            http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd"> 
    
      <service> 
        <jsr107:defaults default-template="defCache"> 
        </jsr107:defaults>
      </service>
    
      <cache-template name="defCache">
        <heap unit="entries">20</heap>
      </cache-template>
    </config>
    

    and set all configuration you like in that cache. This declarative configuration complements or even overrides the programmatic one. Indications of how to specify the max size of a Ehcache can be found here.