SPR-7308
+ add support for multiple cache names + require each annotation to specify a cache name + add method support in Key generator interface + add bug fix for embedded JDK concurrent declaration git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3819 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
2c7f153336
commit
a118023af6
|
|
@ -1,4 +1,4 @@
|
||||||
#Thu Dec 18 06:34:28 PST 2008
|
#Wed Mar 31 18:40:01 EEST 2010
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
|
formatter_profile=_Spring
|
||||||
formatter_settings_version=11
|
formatter_settings_version=11
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.cache;
|
package org.springframework.cache;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache 'key' extractor. Used for creating a key based on the given
|
* Cache 'key' extractor. Used for creating a key based on the given method
|
||||||
* parameters.
|
* (used as context) and its parameter.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
// CL: could be renamed to KeyFactory
|
|
||||||
public interface KeyGenerator<K> {
|
public interface KeyGenerator<K> {
|
||||||
|
|
||||||
K extract(Object... params);
|
K extract(Method method, Object... params);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ public class AnnotationCacheDefinitionSource extends AbstractFallbackCacheDefini
|
||||||
*/
|
*/
|
||||||
protected CacheDefinition determineCacheDefinition(AnnotatedElement ae) {
|
protected CacheDefinition determineCacheDefinition(AnnotatedElement ae) {
|
||||||
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
|
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
|
||||||
CacheDefinition attr = annotationParser.parseTransactionAnnotation(ae);
|
CacheDefinition attr = annotationParser.parseCacheAnnotation(ae);
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,5 +42,5 @@ public interface CacheAnnotationParser {
|
||||||
* or <code>null</code> if none was found
|
* or <code>null</code> if none was found
|
||||||
* @see AnnotationCacheDefinitionSource#determineCacheOperationDefinition
|
* @see AnnotationCacheDefinitionSource#determineCacheOperationDefinition
|
||||||
*/
|
*/
|
||||||
CacheDefinition parseTransactionAnnotation(AnnotatedElement ae);
|
CacheDefinition parseCacheAnnotation(AnnotatedElement ae);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public @interface CacheEvict {
|
||||||
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
||||||
* value (or the bean name(s)) of (a) specific bean definition.
|
* value (or the bean name(s)) of (a) specific bean definition.
|
||||||
*/
|
*/
|
||||||
String value() default "";
|
String[] value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||||
|
|
@ -57,11 +57,11 @@ public @interface CacheEvict {
|
||||||
String condition() default "";
|
String condition() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not all the entries inside the cache are removed or not.
|
* Whether or not all the entries inside the cache(s) are removed or not. By
|
||||||
* By default, only the value under the associated key is removed.
|
* default, only the value under the associated key is removed.
|
||||||
*
|
*
|
||||||
* Note that specifying setting this parameter to true and specifying a
|
* Note that specifying setting this parameter to true and specifying a
|
||||||
* {@link CacheKey key} is not allowed.
|
* {@link CacheKey key} is not allowed.
|
||||||
*/
|
*/
|
||||||
boolean allEntries() default false;
|
boolean allEntries() default false;
|
||||||
}
|
}
|
||||||
|
|
@ -37,11 +37,12 @@ import java.lang.annotation.Target;
|
||||||
public @interface Cacheable {
|
public @interface Cacheable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the cache in which the update takes place.
|
* Name of the caches in which the update takes place.
|
||||||
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
* <p>
|
||||||
* value (or the bean name(s)) of (a) specific bean definition.
|
* May be used to determine the target cache (or caches), matching the
|
||||||
|
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||||
*/
|
*/
|
||||||
String value() default "";
|
String[] value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
|
||||||
import org.springframework.cache.interceptor.CacheInvalidateDefinition;
|
|
||||||
import org.springframework.cache.interceptor.CacheDefinition;
|
import org.springframework.cache.interceptor.CacheDefinition;
|
||||||
|
import org.springframework.cache.interceptor.CacheInvalidateDefinition;
|
||||||
import org.springframework.cache.interceptor.CacheUpdateDefinition;
|
import org.springframework.cache.interceptor.CacheUpdateDefinition;
|
||||||
import org.springframework.cache.interceptor.DefaultCacheInvalidateDefinition;
|
import org.springframework.cache.interceptor.DefaultCacheInvalidateDefinition;
|
||||||
import org.springframework.cache.interceptor.DefaultCacheUpdateDefinition;
|
import org.springframework.cache.interceptor.DefaultCacheUpdateDefinition;
|
||||||
|
|
@ -34,17 +34,17 @@ import org.springframework.cache.interceptor.DefaultCacheUpdateDefinition;
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class SpringCachingAnnotationParser implements CacheAnnotationParser, Serializable {
|
public class SpringCachingAnnotationParser implements CacheAnnotationParser, Serializable {
|
||||||
|
|
||||||
public CacheDefinition parseTransactionAnnotation(AnnotatedElement ae) {
|
public CacheDefinition parseCacheAnnotation(AnnotatedElement ae) {
|
||||||
Cacheable update = findAnnotation(ae, Cacheable.class);
|
Cacheable update = findAnnotation(ae, Cacheable.class);
|
||||||
|
|
||||||
if (update != null) {
|
if (update != null) {
|
||||||
return parseCacheableAnnotation(update);
|
return parseCacheableAnnotation(ae, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheEvict invalidate = findAnnotation(ae, CacheEvict.class);
|
CacheEvict invalidate = findAnnotation(ae, CacheEvict.class);
|
||||||
|
|
||||||
if (invalidate != null) {
|
if (invalidate != null) {
|
||||||
return parseInvalidateAnnotation(invalidate);
|
return parseInvalidateAnnotation(ae, invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -63,22 +63,24 @@ public class SpringCachingAnnotationParser implements CacheAnnotationParser, Ser
|
||||||
return ann;
|
return ann;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CacheUpdateDefinition parseCacheableAnnotation(Cacheable ann) {
|
CacheUpdateDefinition parseCacheableAnnotation(AnnotatedElement target, Cacheable ann) {
|
||||||
DefaultCacheUpdateDefinition dcud = new DefaultCacheUpdateDefinition();
|
DefaultCacheUpdateDefinition dcud = new DefaultCacheUpdateDefinition();
|
||||||
dcud.setCacheName(ann.value());
|
dcud.setCacheNames(ann.value());
|
||||||
dcud.setCondition(ann.condition());
|
dcud.setCondition(ann.condition());
|
||||||
dcud.setKey(ann.key());
|
dcud.setKey(ann.key());
|
||||||
|
dcud.setName(target.toString());
|
||||||
|
|
||||||
return dcud;
|
return dcud;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CacheInvalidateDefinition parseInvalidateAnnotation(CacheEvict ann) {
|
CacheInvalidateDefinition parseInvalidateAnnotation(AnnotatedElement target, CacheEvict ann) {
|
||||||
DefaultCacheInvalidateDefinition dcid = new DefaultCacheInvalidateDefinition();
|
DefaultCacheInvalidateDefinition dcid = new DefaultCacheInvalidateDefinition();
|
||||||
dcid.setCacheName(ann.value());
|
dcid.setCacheNames(ann.value());
|
||||||
dcid.setCondition(ann.condition());
|
dcid.setCondition(ann.condition());
|
||||||
dcid.setKey(ann.key());
|
dcid.setKey(ann.key());
|
||||||
dcid.setCacheWide(ann.allEntries());
|
dcid.setCacheWide(ann.allEntries());
|
||||||
|
dcid.setName(target.toString());
|
||||||
|
|
||||||
return dcid;
|
return dcid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentMap;
|
||||||
import org.springframework.beans.factory.BeanNameAware;
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory bean for easy configuration of {@link ConcurrentCache} through Spring.
|
* Factory bean for easy configuration of {@link ConcurrentCache} through Spring.
|
||||||
|
|
@ -52,7 +53,9 @@ public class ConcurrentCacheFactoryBean<K, V> implements FactoryBean<ConcurrentC
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBeanName(String beanName) {
|
public void setBeanName(String beanName) {
|
||||||
setName(beanName);
|
if (!StringUtils.hasText(name)) {
|
||||||
|
setName(beanName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class implementing {@link CacheDefinition}.
|
* Base class implementing {@link CacheDefinition}.
|
||||||
|
|
@ -24,14 +29,14 @@ package org.springframework.cache.interceptor;
|
||||||
*/
|
*/
|
||||||
abstract class AbstractCacheDefinition implements CacheDefinition {
|
abstract class AbstractCacheDefinition implements CacheDefinition {
|
||||||
|
|
||||||
private String cacheName = "";
|
private Set<String> cacheNames = Collections.emptySet();
|
||||||
private String condition = "";
|
private String condition = "";
|
||||||
private String key = "";
|
private String key = "";
|
||||||
private String name = "";
|
private String name = "";
|
||||||
|
|
||||||
|
|
||||||
public String getCacheName() {
|
public Set<String> getCacheNames() {
|
||||||
return cacheName;
|
return cacheNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCondition() {
|
public String getCondition() {
|
||||||
|
|
@ -47,18 +52,30 @@ abstract class AbstractCacheDefinition implements CacheDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCacheName(String cacheName) {
|
public void setCacheName(String cacheName) {
|
||||||
this.cacheName = cacheName;
|
Assert.hasText(cacheName);
|
||||||
|
this.cacheNames = Collections.singleton(cacheName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheNames(String[] cacheNames) {
|
||||||
|
Assert.notEmpty(cacheNames);
|
||||||
|
this.cacheNames = new LinkedHashSet<String>(cacheNames.length);
|
||||||
|
for (String string : cacheNames) {
|
||||||
|
this.cacheNames.add(string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCondition(String condition) {
|
public void setCondition(String condition) {
|
||||||
|
Assert.notNull(condition);
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(String key) {
|
public void setKey(String key) {
|
||||||
|
Assert.notNull(key);
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
Assert.hasText(name);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,12 +114,15 @@ abstract class AbstractCacheDefinition implements CacheDefinition {
|
||||||
*/
|
*/
|
||||||
protected StringBuilder getDefinitionDescription() {
|
protected StringBuilder getDefinitionDescription() {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
result.append(cacheName);
|
result.append("CacheDefinition[");
|
||||||
result.append(',');
|
result.append(name);
|
||||||
|
result.append("] caches=");
|
||||||
|
result.append(cacheNames);
|
||||||
|
result.append(" | condition='");
|
||||||
result.append(condition);
|
result.append(condition);
|
||||||
result.append(",");
|
result.append("' | key='");
|
||||||
result.append(key);
|
result.append(key);
|
||||||
|
result.append("'");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,9 @@ package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
@ -58,8 +61,11 @@ import org.springframework.util.StringUtils;
|
||||||
public abstract class CacheAspectSupport implements InitializingBean {
|
public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
|
|
||||||
private static class EmptyHolder implements Serializable {
|
private static class EmptyHolder implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: can null values be properly stored into user caches?
|
||||||
private static final Object NULL_RETURN = new EmptyHolder();
|
private static final Object NULL_RETURN = new EmptyHolder();
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
@ -116,21 +122,30 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
cacheDefinitionSources) : cacheDefinitionSources[0]);
|
cacheDefinitionSources) : cacheDefinitionSources[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <K, V> Cache<K, V> getCache(CacheDefinition definition) {
|
protected Collection<Cache<?, ?>> getCaches(CacheDefinition definition) {
|
||||||
// TODO: add support for multiple caches
|
|
||||||
// TODO: add behaviour for the default cache
|
// TODO: add behaviour for the default cache
|
||||||
String name = definition.getCacheName();
|
Set<String> cacheNames = definition.getCacheNames();
|
||||||
if (!StringUtils.hasText(name)) {
|
|
||||||
name = cacheManager.getCacheNames().iterator().next();
|
Collection<Cache<?,?>> caches = new ArrayList<Cache<?,?>>(cacheNames.size());
|
||||||
|
|
||||||
|
for (String cacheName : cacheNames) {
|
||||||
|
Cache<Object, Object> cache = cacheManager.getCache(cacheName);
|
||||||
|
if (cache == null){
|
||||||
|
throw new IllegalArgumentException("Cannot find cache named ["+cacheName+"] for " + definition);
|
||||||
|
}
|
||||||
|
caches.add(cache);
|
||||||
}
|
}
|
||||||
return cacheManager.getCache(name);
|
|
||||||
|
return caches;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheOperationContext getOperationContext(CacheDefinition definition, Method method, Object[] args, Class<?> targetClass) {
|
protected CacheOperationContext getOperationContext(CacheDefinition definition, Method method, Object[] args,
|
||||||
|
Class<?> targetClass) {
|
||||||
return new CacheOperationContext(definition, method, args, targetClass);
|
return new CacheOperationContext(definition, method, args, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object execute(Callable<Object> invocation, Object target, Method method, Object[] args) throws Exception {
|
protected Object execute(Callable<Object> invocation, Object target,
|
||||||
|
Method method, Object[] args) throws Exception {
|
||||||
// get backing class
|
// get backing class
|
||||||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
||||||
|
|
||||||
|
|
@ -138,40 +153,47 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
targetClass = target.getClass();
|
targetClass = target.getClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
final CacheDefinition cacheDef = getCacheDefinitionSource().getCacheDefinition(method,
|
final CacheDefinition cacheDef = getCacheDefinitionSource()
|
||||||
targetClass);
|
.getCacheDefinition(method, targetClass);
|
||||||
|
|
||||||
Object retVal = null;
|
Object retVal = null;
|
||||||
|
|
||||||
// analyze caching information
|
// analyze caching information
|
||||||
if (cacheDef != null) {
|
if (cacheDef != null) {
|
||||||
CacheOperationContext context = getOperationContext(cacheDef, method, args, targetClass);
|
CacheOperationContext context = getOperationContext(cacheDef,
|
||||||
Cache<Object, Object> cache = (Cache<Object, Object>) context.getCache();
|
method, args, targetClass);
|
||||||
|
Collection<Cache<?,?>> caches = context.getCaches();
|
||||||
|
|
||||||
if (context.hasConditionPassed()) {
|
if (context.hasConditionPassed()) {
|
||||||
// check operation
|
// check operation
|
||||||
if (cacheDef instanceof CacheUpdateDefinition) {
|
if (cacheDef instanceof CacheUpdateDefinition) {
|
||||||
|
// for each cache
|
||||||
// check cache first
|
// check cache first
|
||||||
Object key = context.generateKey();
|
for (Cache cache : caches) {
|
||||||
retVal = cache.get(key);
|
Object key = context.generateKey();
|
||||||
if (retVal == null) {
|
retVal = cache.get(key);
|
||||||
retVal = invocation.call();
|
if (retVal == null) {
|
||||||
cache.put(key, (retVal == null ? NULL_RETURN : retVal));
|
retVal = invocation.call();
|
||||||
|
cache.put(key, (retVal == null ? NULL_RETURN : retVal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheDef instanceof CacheInvalidateDefinition) {
|
if (cacheDef instanceof CacheInvalidateDefinition) {
|
||||||
CacheInvalidateDefinition invalidateDef = (CacheInvalidateDefinition) cacheDef;
|
CacheInvalidateDefinition invalidateDef = (CacheInvalidateDefinition) cacheDef;
|
||||||
retVal = invocation.call();
|
retVal = invocation.call();
|
||||||
|
|
||||||
// flush the cache (ignore arguments)
|
// for each cache
|
||||||
if (invalidateDef.isCacheWide()) {
|
|
||||||
cache.clear();
|
for (Cache cache : caches) {
|
||||||
}
|
// flush the cache (ignore arguments)
|
||||||
else {
|
if (invalidateDef.isCacheWide()) {
|
||||||
// check key
|
cache.clear();
|
||||||
Object key = context.generateKey();
|
} else {
|
||||||
cache.remove(key);
|
// check key
|
||||||
|
Object key = context.generateKey();
|
||||||
|
cache.remove(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,23 +207,24 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
protected class CacheOperationContext {
|
protected class CacheOperationContext {
|
||||||
|
|
||||||
private CacheDefinition definition;
|
private CacheDefinition definition;
|
||||||
private final Cache<?, ?> cache;
|
private final Collection<Cache<?, ?>> caches;
|
||||||
private final Method method;
|
private final Method method;
|
||||||
private final Object[] args;
|
private final Object[] args;
|
||||||
|
|
||||||
// context passed around to avoid multiple creations
|
// context passed around to avoid multiple creations
|
||||||
private final EvaluationContext evalContext;
|
private final EvaluationContext evalContext;
|
||||||
|
|
||||||
private final KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
private final KeyGenerator<Object> keyGenerator = new DefaultKeyGenerator();
|
||||||
|
|
||||||
public CacheOperationContext(CacheDefinition operationDefinition, Method method, Object[] args,
|
public CacheOperationContext(CacheDefinition operationDefinition,
|
||||||
Class<?> targetClass) {
|
Method method, Object[] args, Class<?> targetClass) {
|
||||||
this.definition = operationDefinition;
|
this.definition = operationDefinition;
|
||||||
this.cache = CacheAspectSupport.this.getCache(definition);
|
this.caches = CacheAspectSupport.this.getCaches(definition);
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
|
||||||
this.evalContext = evaluator.createEvaluationContext(cache, method, args, targetClass);
|
this.evalContext = evaluator.createEvaluationContext(caches, method,
|
||||||
|
args, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -212,7 +235,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
*/
|
*/
|
||||||
protected boolean hasConditionPassed() {
|
protected boolean hasConditionPassed() {
|
||||||
if (StringUtils.hasText(definition.getCondition())) {
|
if (StringUtils.hasText(definition.getCondition())) {
|
||||||
return evaluator.condition(definition.getCondition(), method, evalContext);
|
return evaluator.condition(definition.getCondition(), method,
|
||||||
|
evalContext);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -221,8 +245,10 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
* Computes the key for the given caching definition.
|
* Computes the key for the given caching definition.
|
||||||
*
|
*
|
||||||
* @param definition
|
* @param definition
|
||||||
* @param method method being invoked
|
* @param method
|
||||||
* @param objects arguments passed during the method invocation
|
* method being invoked
|
||||||
|
* @param objects
|
||||||
|
* arguments passed during the method invocation
|
||||||
* @return generated key (null if none can be generated)
|
* @return generated key (null if none can be generated)
|
||||||
*/
|
*/
|
||||||
protected Object generateKey() {
|
protected Object generateKey() {
|
||||||
|
|
@ -230,11 +256,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
return evaluator.key(definition.getKey(), method, evalContext);
|
return evaluator.key(definition.getKey(), method, evalContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyGenerator.extract(args);
|
return keyGenerator.extract(method, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Cache<?, ?> getCache() {
|
protected Collection<Cache<?, ?>> getCaches() {
|
||||||
return cache;
|
return caches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface describing Spring-compliant caching operation.
|
* Interface describing Spring-compliant caching operation.
|
||||||
*
|
*
|
||||||
|
|
@ -33,11 +35,11 @@ public interface CacheDefinition {
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the cache against which this operation is performed.
|
* Returns the names of the cache against which this operation is performed.
|
||||||
*
|
*
|
||||||
* @return name of the cache on which the operation is performed.
|
* @return names of the cache on which the operation is performed.
|
||||||
*/
|
*/
|
||||||
String getCacheName();
|
Set<String> getCacheNames();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the SpEL expression conditioning the operation.
|
* Returns the SpEL expression conditioning the operation.
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,9 +35,9 @@ interface CacheExpressionRootObject {
|
||||||
String getMethodName();
|
String getMethodName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cache against which the method is executed.
|
* Returns the caches against which the method is executed.
|
||||||
*
|
*
|
||||||
* @return current cache
|
* @return current cache
|
||||||
*/
|
*/
|
||||||
Cache getCache();
|
Collection<Cache<?,?>> getCaches();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
@ -27,19 +29,19 @@ import org.springframework.util.Assert;
|
||||||
public class DefaultCacheExpressionRootObject implements CacheExpressionRootObject {
|
public class DefaultCacheExpressionRootObject implements CacheExpressionRootObject {
|
||||||
|
|
||||||
private final String methodName;
|
private final String methodName;
|
||||||
private final Cache cache;
|
private final Collection<Cache<?, ?>> caches;
|
||||||
|
|
||||||
public DefaultCacheExpressionRootObject(Cache cache, String methodName) {
|
public DefaultCacheExpressionRootObject(Collection<Cache<?,?>> caches, String methodName) {
|
||||||
Assert.hasText(methodName, "method name is required");
|
Assert.hasText(methodName, "method name is required");
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.cache = cache;
|
this.caches = caches;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethodName() {
|
public String getMethodName() {
|
||||||
return methodName;
|
return methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cache getCache() {
|
public Collection<Cache<?, ?>> getCaches() {
|
||||||
return cache;
|
return caches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
@ -46,8 +47,8 @@ class ExpressionEvaluator {
|
||||||
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
||||||
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
||||||
|
|
||||||
EvaluationContext createEvaluationContext(Cache<?, ?> cache, Method method, Object[] args, Class<?> targetClass) {
|
EvaluationContext createEvaluationContext(Collection<Cache<?, ?>> caches, Method method, Object[] args, Class<?> targetClass) {
|
||||||
DefaultCacheExpressionRootObject rootObject = new DefaultCacheExpressionRootObject(cache, method.getName());
|
DefaultCacheExpressionRootObject rootObject = new DefaultCacheExpressionRootObject(caches, method.getName());
|
||||||
StandardEvaluationContext evaluationContext = new LazyParamAwareEvaluationContext(rootObject,
|
StandardEvaluationContext evaluationContext = new LazyParamAwareEvaluationContext(rootObject,
|
||||||
paramNameDiscoverer, method, args, targetClass, targetMethodCache);
|
paramNameDiscoverer, method, args, targetClass, targetMethodCache);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,19 @@
|
||||||
|
|
||||||
package org.springframework.cache.support;
|
package org.springframework.cache.support;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.springframework.cache.KeyGenerator;
|
import org.springframework.cache.KeyGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Default key generator. Computes a resulting key based on the hashcode of the
|
||||||
|
* given parameters.
|
||||||
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class DefaultKeyGenerator implements KeyGenerator<Object> {
|
public class DefaultKeyGenerator implements KeyGenerator<Object> {
|
||||||
|
|
||||||
public Object extract(Object... params) {
|
public Object extract(Method method, Object... params) {
|
||||||
int hashCode = 17;
|
int hashCode = 17;
|
||||||
|
|
||||||
for (Object object : params) {
|
for (Object object : params) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import org.springframework.cache.annotation.Cacheable;
|
||||||
/**
|
/**
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
@Cacheable
|
@Cacheable("default")
|
||||||
public class AnnotatedClassCacheableService implements CacheableService {
|
public class AnnotatedClassCacheableService implements CacheableService {
|
||||||
|
|
||||||
private AtomicLong counter = new AtomicLong();
|
private AtomicLong counter = new AtomicLong();
|
||||||
|
|
@ -37,11 +37,11 @@ public class AnnotatedClassCacheableService implements CacheableService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CacheEvict
|
@CacheEvict("default")
|
||||||
public void invalidate(Object arg1) {
|
public void invalidate(Object arg1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cacheable(key = "#p0")
|
@Cacheable(value = "default", key = "#p0")
|
||||||
public Object key(Object arg1, Object arg2) {
|
public Object key(Object arg1, Object arg2) {
|
||||||
return counter.getAndIncrement();
|
return counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,21 +31,21 @@ public class DefaultCacheableService implements CacheableService<Long> {
|
||||||
|
|
||||||
private AtomicLong counter = new AtomicLong();
|
private AtomicLong counter = new AtomicLong();
|
||||||
|
|
||||||
@Cacheable
|
@Cacheable("default")
|
||||||
public Long cache(Object arg1) {
|
public Long cache(Object arg1) {
|
||||||
return counter.getAndIncrement();
|
return counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@CacheEvict
|
@CacheEvict("default")
|
||||||
public void invalidate(Object arg1) {
|
public void invalidate(Object arg1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cacheable(condition = "#classField == 3")
|
@Cacheable(value = "default", condition = "#classField == 3")
|
||||||
public Long conditional(int classField) {
|
public Long conditional(int classField) {
|
||||||
return counter.getAndIncrement();
|
return counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cacheable(key = "#p0")
|
@Cacheable(value = "default", key = "#p0")
|
||||||
public Long key(Object arg1, Object arg2) {
|
public Long key(Object arg1, Object arg2) {
|
||||||
return counter.getAndIncrement();
|
return counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue