6
\$\begingroup\$

Details about spring's caching framework are here. When I was reading this link, I thought the composite cache mentioned there was one that used levels of caching based on the order given to the constructor. On reading the documentation here, I realized that it was not so; this was so that different caching solutions could be used in different methods.

With the following code, one can have a GuavaCache as L1 as that uses plain Java objects and wouldn't incur network latency or serialization and deserialization overhead. In case of a miss in L1 one would perform a get from L2 (and put it in L1 if found there). For L2 one might use a distributed caching solution - probably a cache running on another fleet of hosts.

TwoLevelCacheManager

package hello;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.NoOpCacheManager;
import java.util.Collection;
public class TwoLevelCacheManager implements CacheManager {
 CacheManager currentLevel;
 CacheManager nextLevel;
 TwoLevelCacheManager(CacheManager singleLevel) {
 this(singleLevel, new NoOpCacheManager());
 }
 TwoLevelCacheManager(CacheManager currentLevel, CacheManager nextLevel) {
 //assert both contain same cache names or dynamic creation true?
 this.currentLevel = currentLevel;
 this.nextLevel = nextLevel;
 }
 @Override
 public Cache getCache(String name) {
 return new TwoLevelCacheCache(name, currentLevel.getCache(name), nextLevel.getCache(name));
 }
 @Override
 public Collection<String> getCacheNames() {
 return currentLevel.getCacheNames();
 }
}

TwoLevelCacheCache

package hello;
import org.springframework.cache.Cache;
public class TwoLevelCacheCache implements Cache {
 private String name;
 private Cache levelOneCache;
 private Cache nextLevelCache;
 TwoLevelCacheCache(String name, Cache cache) {
 this(name, cache, new NoOpCache(name));
 }
 TwoLevelCacheCache(String name, Cache levelOneCache, Cache nextLevelCache) {
 this.name = name;
 this.levelOneCache = levelOneCache;
 this.nextLevelCache = nextLevelCache;
 }
 @Override
 public String getName() {
 return name;
 }
 @Override
 public Object getNativeCache() {
 return this;
 }
 @Override
 public ValueWrapper get(Object o) {
 ValueWrapper value = levelOneCache.get(o);
 if (value == null) {
 value = nextLevelCache.get(o);
 if (value != null) {
 levelOneCache.put(o, value.get());
 }
 }
 return value;
 }
 @Override
 public <T> T get(Object o, Class<T> aClass) {
 T value = levelOneCache.get(o, aClass);
 if (value == null) {
 value = nextLevelCache.get(o, aClass);
 if (value != null) {
 levelOneCache.put(o, value);
 }
 }
 return value;
 }
 @Override
 public void put(Object o, Object o1) {
 levelOneCache.put(o, o1);
 nextLevelCache.put(o, o1);
 }
 @Override
 public ValueWrapper putIfAbsent(Object o, Object o1) {
 //synchronize?
 ValueWrapper value = get(o);
 if (value == null) {
 put(o, o1);
 }
 return value;
 }
 @Override
 public void evict(Object o) {
 levelOneCache.evict(o);
 nextLevelCache.evict(o);
 }
 @Override
 public void clear() {
 levelOneCache.clear();
 nextLevelCache.clear();
 }
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Dec 25, 2015 at 5:22
\$\endgroup\$
1
  • \$\begingroup\$ TwoLevelCacheCache class name should be changed to TwoLevelCache. We should make get(Object 0) and put(Object o, Object o1) thread safe. \$\endgroup\$ Commented Mar 19, 2019 at 16:48

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.