2

I create a spring boot project use jcache, config like this:

spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
spring.cache.jcache.config=classpath:ehcache.xml

I want to create cache dynamically, my code like this:

@Autowired
lateinit var cacheManager: CacheManager;

@RequestMapping("setCache")
fun setCache(key: String, v: String) {
    cacheManager.getCache("test").put(key, v)
}

@RequestMapping("getCache")
fun getCache(key: String) {
    val  v = cacheManager.getCache("test")[key]
    println(v)
}

but I can't get cache when cache doesn't exist, I want to create cache dynamically.

UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
tedeum
  • 185
  • 3
  • 14

1 Answers1

1

I came around the same issue. There are basically two options.

  • Either you create and wrap the CacheManager during the CacheManager creation in your Spring Boot Cache Configuration
  • OR You use an own implementation of an CacheResolver in the @Cacheable annotation
import javax.cache.CacheManager;
import javax.cache.spi.CachingProvider;

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager extendedCacheManager() {
        CachingProvider provider = Caching.getCachingProvider();
        // get the cache manager according your provider you have chosen
        CacheManager cacheManager = provider.getCacheManager(...);
        // wrap it with your own implementation
        return new MyCacheManager(cacheManager);
    }
}

Own CacheManager Wrapper

import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.Configuration;
import javax.cache.configuration.MutableConfiguration;

public class MyCacheManager implements CacheManager {

    CacheManager cacheManager;

    public MyCacheManager(CacheManager cacheManager) {
        super();
        this.cacheManager = cacheManager;
    }

   ...

    public <K, V> Cache<K, V> getCache(String cacheName, Class<K> keyType, Class<V> valueType) {
        Cache<K, V> cache = cacheManager.getCache(cacheName, keyType, valueType);
        if (cache == null) {
            MutableConfiguration<K, V> configuration = new MutableConfiguration<>();
            cache = this.cacheManager.createCache(cacheName, configuration);
        }
        return cache;
    }

}

For to the other possibility via CacheResolver. First you need an own implementation of the interface javax.cache.annotation.CacheResolver and javax.cache.annotation.CacheResolverFactory. you can do this in the same class or having separate classes.

import javax.cache.annotation.CacheResolver;
import javax.cache.annotation.CacheResolverFactory;


import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.MutableConfiguration;

public class AutoCacheResolverFactory implements CacheResolverFactory, CacheResolver {

    CacheManager cacheManager;

    public AutoCacheResolverFactory(CacheManager cacheManager) {
        super();
        this.cacheManager = cacheManager;
    }

    // from interface CacheResolverFactory

    @Override
    public CacheResolver getCacheResolver(CacheMethodDetails<? extends Annotation> cacheMethodDetails) {
        return this;
    }

    @Override
    public CacheResolver getExceptionCacheResolver(CacheMethodDetails<CacheResult> cacheMethodDetails) {
        return this;
    }

     // from interface CacheResolver 

     public <K, V> javax.cache.Cache<K, V> resolveCache(CacheInvocationContext<?> cacheInvocationContext) {
        String cacheName = cacheInvocationContext.getCacheName();
        javax.cache.Cache<K, V> cache = cacheManager.getCache(cacheName);
        if (cache == null) {
            MutableConfiguration<K, V> configuration = new MutableConfiguration<>();
            cache = this.cacheManager.createCache(cacheName, configuration);
        }
        return cache;
    }

}

and then at your method where you like to cache the results use the annotation accordingly.

import javax.cache.annotation.CacheResult;

public class MyService { 
...
   @CacheResult(cacheResolverFactory= AutoCacheResolverFactory.class) 
   public List<MyExpensiveResult> getExpensiveResult(...){
      ...
   }
}


megloff
  • 1,400
  • 4
  • 27
  • 44