Search code examples
spring-bootspring-data-redisspring-cachecaffeine

L1 + L2 caching strategy using Spring Cacheable


I am trying to setup L1 + L2 caching strategy to use with @Cacheable annotation. My objective is

  1. Configure Caffeine Cache
  2. Configure Redis Cache
  3. Look up item in Caffeine Cache, if found return, else step 4
  4. Look up item in Redis Cache, if found return and cache in caffeine, else step 5
  5. Use real service to return the result.

I know this is not supported out of the box, but i have been trying to read the documentation on how to go about wiring up such a solution.

My current solution is to wrap my actual service is a RedisBackedService which has the redisCacheManager on the cacheable annotation which in turn is wrapped in a CaffeineBackedService which has a caffeineCacheManager on the cacheable annotation. Needless to say it seems redundant.

Any pointers would be helpful.


Solution

  • So to conclude here and provide an answer based on the comments, this is not a feature of the cache abstraction but the SPI of the cache abstraction is simple enough for you to implement something yourself.

    public class FallbackCache implements Cache {
    
      private final Cache primaryCache;
      private final Cache fallbackCache;
    
      FallbackCache(Cache primaryCache, Cache fallbackCache) { ... }
    
      public ValueWrapper get(Object key) {
        ValueWrapper wrapper = primaryCache.get(key);
        if (wrapper != null) {
          return wrapper;
        }
        return fallbackCache.get(key);
      }
    
      // other methods
    
    }
    

    Some methods like the native cache accessor can be a bit tricky for this use case. I'd return the primary cache and hide the fact that there is a fallback from the caller.

    If you know your caches upfront, then you can create them and wrap them in a SimpleCacheManager. If you need to create them on the fly, the CacheManager API requires you to implement two simple methods.