revised cache abstraction

- removed generics from Cache/CacheManager (they add no value since it's an SPI not API)
+ update docs and tests
+ renamed ConcurrentCacheFactoryBean to ConcurrentMapCacheFactoryBean
This commit is contained in:
Costin Leau 2011-05-18 18:34:41 +00:00
parent dadd0f57ee
commit b39673aa79
19 changed files with 63 additions and 67 deletions

View File

@ -19,7 +19,7 @@
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
</set>
</property>
</bean>

View File

@ -26,18 +26,18 @@ package org.springframework.cache;
*
* @author Costin Leau
*/
public interface Cache<K, V> {
public interface Cache {
/**
* A (wrapper) object representing a cache value.
*/
interface ValueWrapper<V> {
interface ValueWrapper {
/**
* Returns the actual value in the cache.
*
* @return cache value
*/
V get();
Object get();
}
/**
@ -62,7 +62,7 @@ public interface Cache<K, V> {
* @return the value to which this cache maps the specified key, or
* <tt>null</tt> if the cache contains no mapping for this key.
*/
ValueWrapper<V> get(Object key);
ValueWrapper get(Object key);
/**
* Associates the specified value with the specified key in this cache.
@ -72,7 +72,7 @@ public interface Cache<K, V> {
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
*/
void put(K key, V value);
void put(Object key, Object value);
/**
* Evicts the mapping for this key from this cache if it is present.

View File

@ -32,7 +32,7 @@ public interface CacheManager {
* @param name cache identifier - cannot be null
* @return associated cache or null if none is found
*/
<K, V> Cache<K, V> getCache(String name);
Cache getCache(String name);
/**
* Returns a collection of the caches known by this cache manager.

View File

@ -34,14 +34,14 @@ import org.springframework.cache.interceptor.DefaultValueWrapper;
*
* @author Costin Leau
*/
public class ConcurrentMapCache<K, V> implements Cache<K, V> {
public class ConcurrentMapCache implements Cache {
private static class NullHolder implements Serializable {
private static final long serialVersionUID = 1L;
}
private static final Object NULL_HOLDER = new NullHolder();
private final ConcurrentMap<K, V> store;
private final ConcurrentMap store;
private final String name;
private final boolean allowNullValues;
@ -50,10 +50,10 @@ public class ConcurrentMapCache<K, V> implements Cache<K, V> {
}
public ConcurrentMapCache(String name) {
this(new ConcurrentHashMap<K, V>(), name, true);
this(new ConcurrentHashMap(), name, true);
}
public ConcurrentMapCache(ConcurrentMap<K, V> delegate, String name, boolean allowNullValues) {
public ConcurrentMapCache(ConcurrentMap delegate, String name, boolean allowNullValues) {
this.store = delegate;
this.name = name;
this.allowNullValues = allowNullValues;
@ -67,7 +67,7 @@ public class ConcurrentMapCache<K, V> implements Cache<K, V> {
return allowNullValues;
}
public ConcurrentMap<K, V> getNativeCache() {
public ConcurrentMap getNativeCache() {
return store;
}
@ -75,13 +75,12 @@ public class ConcurrentMapCache<K, V> implements Cache<K, V> {
store.clear();
}
public ValueWrapper<V> get(Object key) {
V v = store.get(key);
return (v != null ? new DefaultValueWrapper<V>(filterNull(v)) : null);
public ValueWrapper get(Object key) {
Object v = store.get(key);
return (v != null ? new DefaultValueWrapper(filterNull(v)) : null);
}
@SuppressWarnings("unchecked")
public void put(K key, V value) {
public void put(Object key, Object value) {
if (allowNullValues && value == null) {
Map map = store;
map.put(key, NULL_HOLDER);
@ -94,7 +93,7 @@ public class ConcurrentMapCache<K, V> implements Cache<K, V> {
store.remove(key);
}
protected V filterNull(V val) {
protected Object filterNull(Object val) {
if (allowNullValues && val == NULL_HOLDER) {
return null;
}

View File

@ -28,19 +28,19 @@ import org.springframework.util.StringUtils;
*
* @author Costin Leau
*/
public class ConcurrentCacheFactoryBean<K, V> implements FactoryBean<ConcurrentMapCache<K, V>>, BeanNameAware,
public class ConcurrentMapCacheFactoryBean implements FactoryBean<ConcurrentMapCache>, BeanNameAware,
InitializingBean {
private String name = "";
private ConcurrentMapCache<K, V> cache;
private ConcurrentMapCache cache;
private ConcurrentMap<K, V> store;
private ConcurrentMap store;
public void afterPropertiesSet() {
cache = (store == null ? new ConcurrentMapCache<K, V>(name) : new ConcurrentMapCache<K, V>(store, name, true));
cache = (store == null ? new ConcurrentMapCache(name) : new ConcurrentMapCache(store, name, true));
}
public ConcurrentMapCache<K, V> getObject() throws Exception {
public ConcurrentMapCache getObject() throws Exception {
return cache;
}
@ -62,7 +62,7 @@ public class ConcurrentCacheFactoryBean<K, V> implements FactoryBean<ConcurrentM
this.name = name;
}
public void setStore(ConcurrentMap<K, V> store) {
public void setStore(ConcurrentMap store) {
this.store = store;
}
}

View File

@ -29,7 +29,7 @@ import org.springframework.util.Assert;
*
* @author Costin Leau
*/
public class EhCacheCache implements Cache<Object, Object> {
public class EhCacheCache implements Cache {
private final Ehcache cache;
@ -58,7 +58,7 @@ public class EhCacheCache implements Cache<Object, Object> {
cache.removeAll();
}
public ValueWrapper<Object> get(Object key) {
public ValueWrapper get(Object key) {
Element element = cache.get(key);
return (element != null ? new DefaultValueWrapper<Object>(element.getObjectValue()) : null);
}

View File

@ -36,7 +36,7 @@ public class EhCacheCacheManager extends AbstractCacheManager {
private net.sf.ehcache.CacheManager cacheManager;
@Override
protected Collection<Cache<?, ?>> loadCaches() {
protected Collection<Cache> loadCaches() {
Assert.notNull(cacheManager, "a backing Ehcache cache manager is required");
Status status = cacheManager.getStatus();
@ -44,7 +44,7 @@ public class EhCacheCacheManager extends AbstractCacheManager {
"an 'alive' Ehcache cache manager is required - current cache is " + status.toString());
String[] names = cacheManager.getCacheNames();
Collection<Cache<?, ?>> caches = new LinkedHashSet<Cache<?, ?>>(names.length);
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
for (String name : names) {
caches.add(new EhCacheCache(cacheManager.getEhcache(name)));
@ -53,8 +53,7 @@ public class EhCacheCacheManager extends AbstractCacheManager {
return caches;
}
@SuppressWarnings("unchecked")
public <K, V> Cache<K, V> getCache(String name) {
public Cache getCache(String name) {
Cache cache = super.getCache(name);
if (cache == null) {
// check the Ehcache cache again

View File

@ -124,13 +124,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
cacheDefinitionSources) : cacheDefinitionSources[0]);
}
protected Collection<Cache<?, ?>> getCaches(CacheOperation operation) {
protected Collection<Cache> getCaches(CacheOperation operation) {
Set<String> cacheNames = operation.getCacheNames();
Collection<Cache<?, ?>> caches = new ArrayList<Cache<?, ?>>(cacheNames.size());
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
for (String cacheName : cacheNames) {
Cache<Object, Object> cache = cacheManager.getCache(cacheName);
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
}
@ -145,7 +145,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
return new CacheOperationContext(operation, method, args, target, targetClass);
}
@SuppressWarnings("unchecked")
protected Object execute(Callable<Object> invocation, Object target, Method method, Object[] args) throws Exception {
// get backing class
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
@ -163,7 +162,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
// analyze caching information
if (cacheOp != null) {
CacheOperationContext context = getOperationContext(cacheOp, method, args, target, targetClass);
Collection<Cache<?, ?>> caches = context.getCaches();
Collection<Cache> caches = context.getCaches();
if (context.hasConditionPassed()) {
// check operation
@ -183,9 +182,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
// for each cache
boolean cacheHit = false;
for (Iterator<Cache<?, ?>> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) {
for (Iterator<Cache> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) {
Cache cache = iterator.next();
Cache.ValueWrapper<Object> wrapper = cache.get(key);
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper != null) {
cacheHit = true;
@ -255,7 +254,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
protected class CacheOperationContext {
private CacheOperation operation;
private final Collection<Cache<?, ?>> caches;
private final Collection<Cache> caches;
private final Object target;
private final Method method;
private final Object[] args;
@ -307,7 +306,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
return keyGenerator.extract(target, method, args);
}
protected Collection<Cache<?, ?>> getCaches() {
protected Collection<Cache> getCaches() {
return caches;
}
}

View File

@ -68,5 +68,5 @@ interface CacheExpressionRootObject {
*
* @return current cache
*/
Collection<Cache<?,?>> getCaches();
Collection<Cache> getCaches();
}

View File

@ -33,10 +33,10 @@ public class DefaultCacheExpressionRootObject implements CacheExpressionRootObje
private final Class<?> targetClass;
private final String methodName;
private final Method method;
private final Collection<Cache<?, ?>> caches;
private final Collection<Cache> caches;
private final Object[] args;
public DefaultCacheExpressionRootObject(Collection<Cache<?, ?>> caches, Method method, Object[] args,
public DefaultCacheExpressionRootObject(Collection<Cache> caches, Method method, Object[] args,
Object target, Class<?> targetClass) {
Assert.notNull(method, "method is required");
Assert.notNull(targetClass, "targetClass is required");
@ -52,7 +52,7 @@ public class DefaultCacheExpressionRootObject implements CacheExpressionRootObje
return methodName;
}
public Collection<Cache<?, ?>> getCaches() {
public Collection<Cache> getCaches() {
return caches;
}

View File

@ -23,15 +23,15 @@ import org.springframework.cache.Cache.ValueWrapper;
*
* @author Costin Leau
*/
public class DefaultValueWrapper<V> implements ValueWrapper<V> {
public class DefaultValueWrapper<V> implements ValueWrapper {
private final V value;
private final Object value;
public DefaultValueWrapper(V value) {
public DefaultValueWrapper(Object value) {
this.value = value;
}
public V get() {
public Object get() {
return value;
}
}

View File

@ -47,7 +47,7 @@ class ExpressionEvaluator {
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
EvaluationContext createEvaluationContext(Collection<Cache<?, ?>> caches, Method method, Object[] args,
EvaluationContext createEvaluationContext(Collection<Cache> caches, Method method, Object[] args,
Object target, Class<?> targetClass) {
DefaultCacheExpressionRootObject rootObject = new DefaultCacheExpressionRootObject(caches, method, args,
target, targetClass);

View File

@ -37,11 +37,11 @@ import org.springframework.util.Assert;
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
// fast lookup by name map
private final ConcurrentMap<String, Cache<?, ?>> caches = new ConcurrentHashMap<String, Cache<?, ?>>();
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private Collection<String> names;
public void afterPropertiesSet() {
Collection<Cache<?, ?>> cacheSet = loadCaches();
Collection<Cache> cacheSet = loadCaches();
Assert.notEmpty(cacheSet);
@ -50,7 +50,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
// preserve the initial order of the cache names
Set<String> cacheNames = new LinkedHashSet<String>(cacheSet.size());
for (Cache<?, ?> cache : cacheSet) {
for (Cache cache : cacheSet) {
caches.put(cache.getName(), cache);
cacheNames.add(cache.getName());
}
@ -64,20 +64,19 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
*
* @param caches the collection of caches handled by the manager
*/
protected abstract Collection<Cache<?, ?>> loadCaches();
protected abstract Collection<Cache> loadCaches();
/**
* Returns the internal cache map.
*
* @return internal cache map
*/
protected final ConcurrentMap<String, Cache<?, ?>> getCacheMap() {
protected final ConcurrentMap<String, Cache> getCacheMap() {
return caches;
}
@SuppressWarnings("unchecked")
public <K, V> Cache<K, V> getCache(String name) {
return (Cache<K, V>) caches.get(name);
public Cache getCache(String name) {
return caches.get(name);
}
public Collection<String> getCacheNames() {

View File

@ -35,8 +35,8 @@ public class CompositeCacheManager implements CacheManager {
private CacheManager[] cacheManagers;
public <K, V> Cache<K, V> getCache(String name) {
Cache<K, V> cache = null;
public Cache getCache(String name) {
Cache cache = null;
for (CacheManager cacheManager : cacheManagers) {
cache = cacheManager.getCache(name);
if (cache != null) {

View File

@ -28,14 +28,14 @@ import org.springframework.cache.Cache;
*/
public class SimpleCacheManager extends AbstractCacheManager {
private Collection<Cache<?, ?>> caches;
private Collection<Cache> caches;
@Override
protected Collection<Cache<?, ?>> loadCaches() {
protected Collection<Cache> loadCaches() {
return caches;
}
public void setCaches(Collection<Cache<?, ?>> caches) {
public void setCaches(Collection<Cache> caches) {
this.caches = caches;
}
}

View File

@ -133,7 +133,7 @@ public abstract class AbstractAnnotationTest {
Object key = new Object();
Object r1 = service.name(key);
assertSame(r1, service.name(key));
Cache<Object, Object> cache = cm.getCache("default");
Cache cache = cm.getCache("default");
// assert the method name is used
assertNotNull(cache.get(keyName));
}
@ -142,7 +142,7 @@ public abstract class AbstractAnnotationTest {
Object key = new Object();
Object r1 = service.rootVars(key);
assertSame(r1, service.rootVars(key));
Cache<Object, Object> cache = cm.getCache("default");
Cache cache = cm.getCache("default");
// assert the method name is used
String expectedKey = "rootVarsrootVars" + AopProxyUtils.ultimateTargetClass(service) + service;
assertNotNull(cache.get(expectedKey));

View File

@ -29,7 +29,7 @@
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
</set>
</property>
</bean>

View File

@ -16,7 +16,7 @@
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
</set>
</property>
</bean>

View File

@ -400,8 +400,8 @@ public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)]]><
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="books"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/>
</set>
</property>
</bean>]]></programlisting>