+ fix internal cache causing the multiple annotations key/conditions to overlap
This commit is contained in:
Costin Leau 2011-11-30 15:21:09 +00:00
parent 91c14bd1fe
commit 0a611aa776
8 changed files with 48 additions and 24 deletions

View File

@ -225,14 +225,14 @@ public abstract class CacheAspectSupport implements InitializingBean {
} }
private void inspectBeforeCacheEvicts(Collection<CacheOperationContext> evictions) { private void inspectBeforeCacheEvicts(Collection<CacheOperationContext> evictions) {
inspectAfterCacheEvicts(evictions, false); inspectCacheEvicts(evictions, false);
} }
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions) { private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions) {
inspectAfterCacheEvicts(evictions, true); inspectCacheEvicts(evictions, true);
} }
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions, boolean afterInvocation) { private void inspectCacheEvicts(Collection<CacheOperationContext> evictions, boolean afterInvocation) {
if (!evictions.isEmpty()) { if (!evictions.isEmpty()) {
@ -276,8 +276,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
} }
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) { private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>( Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
cacheables.size());
boolean updateRequire = false; boolean updateRequire = false;
Object retVal = null; Object retVal = null;
@ -439,8 +438,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
// context passed around to avoid multiple creations // context passed around to avoid multiple creations
private final EvaluationContext evalContext; private final EvaluationContext evalContext;
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target, public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
Class<?> targetClass) {
this.operation = operation; this.operation = operation;
this.caches = CacheAspectSupport.this.getCaches(operation); this.caches = CacheAspectSupport.this.getCaches(operation);
this.target = target; this.target = target;
@ -472,4 +470,4 @@ public abstract class CacheAspectSupport implements InitializingBean {
return this.caches; return this.caches;
} }
} }
} }

View File

@ -114,7 +114,8 @@ public abstract class CacheOperation {
*/ */
protected StringBuilder getOperationDescription() { protected StringBuilder getOperationDescription() {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append("CacheOperation["); result.append(getClass().getSimpleName());
result.append("[");
result.append(this.name); result.append(this.name);
result.append("] caches="); result.append("] caches=");
result.append(this.cacheNames); result.append(this.cacheNames);

View File

@ -44,11 +44,11 @@ class ExpressionEvaluator {
// shared param discoverer since it caches data internally // shared param discoverer since it caches data internally
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>(); private Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>();
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>(); private Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>();
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>(); private Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>();
public EvaluationContext createEvaluationContext( public EvaluationContext createEvaluationContext(
@ -61,21 +61,32 @@ class ExpressionEvaluator {
} }
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) { public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
Expression condExp = this.conditionCache.get(method); String key = toString(method, conditionExpression);
Expression condExp = this.conditionCache.get(key);
if (condExp == null) { if (condExp == null) {
condExp = this.parser.parseExpression(conditionExpression); condExp = this.parser.parseExpression(conditionExpression);
this.conditionCache.put(method, condExp); this.conditionCache.put(key, condExp);
} }
return condExp.getValue(evalContext, boolean.class); return condExp.getValue(evalContext, boolean.class);
} }
public Object key(String keyExpression, Method method, EvaluationContext evalContext) { public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
Expression keyExp = this.keyCache.get(method); String key = toString(method, keyExpression);
Expression keyExp = this.keyCache.get(key);
if (keyExp == null) { if (keyExp == null) {
keyExp = this.parser.parseExpression(keyExpression); keyExp = this.parser.parseExpression(keyExpression);
this.keyCache.put(method, keyExp); this.keyCache.put(key, keyExp);
} }
return keyExp.getValue(evalContext); return keyExp.getValue(evalContext);
} }
} private String toString(Method method, String expression) {
StringBuilder sb = new StringBuilder();
sb.append(method.getDeclaringClass().getName());
sb.append("#");
sb.append(method.toString());
sb.append("#");
sb.append(expression);
return sb.toString();
}
}

View File

@ -45,13 +45,13 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
private final Class<?> targetClass; private final Class<?> targetClass;
private final Map<Method, Method> methodCache; private final Map<String, Method> methodCache;
private boolean paramLoaded = false; private boolean paramLoaded = false;
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method, LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) { Object[] args, Class<?> targetClass, Map<String, Method> methodCache) {
super(rootObject); super(rootObject);
this.paramDiscoverer = paramDiscoverer; this.paramDiscoverer = paramDiscoverer;
@ -85,13 +85,14 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
return; return;
} }
Method targetMethod = this.methodCache.get(this.method); String mKey = toString(this.method);
Method targetMethod = this.methodCache.get(mKey);
if (targetMethod == null) { if (targetMethod == null) {
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass); targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
if (targetMethod == null) { if (targetMethod == null) {
targetMethod = this.method; targetMethod = this.method;
} }
this.methodCache.put(this.method, targetMethod); this.methodCache.put(mKey, targetMethod);
} }
// save arguments as indexed variables // save arguments as indexed variables
@ -108,4 +109,11 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
} }
} }
} private String toString(Method m) {
StringBuilder sb = new StringBuilder();
sb.append(m.getDeclaringClass().getName());
sb.append("#");
sb.append(m.toString());
return sb.toString();
}
}

View File

@ -307,6 +307,8 @@ public abstract class AbstractAnnotationTests {
public void testMultiEvict(CacheableService<?> service) { public void testMultiEvict(CacheableService<?> service) {
Object o1 = new Object(); Object o1 = new Object();
Object o2 = o1.toString() + "A";
Object r1 = service.multiCache(o1); Object r1 = service.multiCache(o1);
Object r2 = service.multiCache(o1); Object r2 = service.multiCache(o1);
@ -314,6 +316,7 @@ public abstract class AbstractAnnotationTests {
Cache primary = cm.getCache("primary"); Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary"); Cache secondary = cm.getCache("secondary");
primary.put(o2, o2);
assertSame(r1, r2); assertSame(r1, r2);
assertSame(r1, primary.get(o1).get()); assertSame(r1, primary.get(o1).get());
assertSame(r1, secondary.get(o1).get()); assertSame(r1, secondary.get(o1).get());
@ -321,6 +324,7 @@ public abstract class AbstractAnnotationTests {
service.multiEvict(o1); service.multiEvict(o1);
assertNull(primary.get(o1)); assertNull(primary.get(o1));
assertNull(secondary.get(o1)); assertNull(secondary.get(o1));
assertNull(primary.get(o2));
Object r3 = service.multiCache(o1); Object r3 = service.multiCache(o1);
Object r4 = service.multiCache(o1); Object r4 = service.multiCache(o1);

View File

@ -116,7 +116,7 @@ public class AnnotatedClassCacheableService implements CacheableService<Object>
return counter.getAndIncrement(); return counter.getAndIncrement();
} }
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") })
public Object multiEvict(Object arg1) { public Object multiEvict(Object arg1) {
return counter.getAndIncrement(); return counter.getAndIncrement();
} }

View File

@ -122,7 +122,7 @@ public class DefaultCacheableService implements CacheableService<Long> {
return counter.getAndIncrement(); return counter.getAndIncrement();
} }
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") })
public Long multiEvict(Object arg1) { public Long multiEvict(Object arg1) {
return counter.getAndIncrement(); return counter.getAndIncrement();
} }

View File

@ -34,6 +34,7 @@
</cache:caching> </cache:caching>
<cache:caching method="multiEvict"> <cache:caching method="multiEvict">
<cache:cache-evict cache="primary"/> <cache:cache-evict cache="primary"/>
<cache:cache-evict cache="primary" key="#p0 + 'A'"/>
<cache:cache-evict method="multiEvict" cache="secondary" key="#p0"/> <cache:cache-evict method="multiEvict" cache="secondary" key="#p0"/>
</cache:caching> </cache:caching>
<cache:caching> <cache:caching>
@ -72,6 +73,7 @@
<cache:cacheable method="multiCache" cache="secondary"/> <cache:cacheable method="multiCache" cache="secondary"/>
<cache:cache-evict method="multiEvict" cache="primary"/> <cache:cache-evict method="multiEvict" cache="primary"/>
<cache:cache-evict method="multiEvict" cache="secondary" key="#p0"/> <cache:cache-evict method="multiEvict" cache="secondary" key="#p0"/>
<cache:cache-evict method="multiEvict" cache="primary" key="#p0 + 'A'"/>
<cache:cacheable method="multiCacheAndEvict" cache="primary" key="#root.methodName"/> <cache:cacheable method="multiCacheAndEvict" cache="primary" key="#root.methodName"/>
<cache:cache-evict method="multiCacheAndEvict" cache="secondary"/> <cache:cache-evict method="multiCacheAndEvict" cache="secondary"/>
<cache:cacheable method="multiConditionalCacheAndEvict" cache="primary" condition="#p0 == 3"/> <cache:cacheable method="multiConditionalCacheAndEvict" cache="primary" condition="#p0 == 3"/>