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:
parent
dadd0f57ee
commit
b39673aa79
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,5 +68,5 @@ interface CacheExpressionRootObject {
|
|||
*
|
||||
* @return current cache
|
||||
*/
|
||||
Collection<Cache<?,?>> getCaches();
|
||||
Collection<Cache> getCaches();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue