@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 201 0 - 2011 the original author or authors .
* Copyright 2002 - 2011 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -25,12 +25,11 @@ import java.util.concurrent.Callable;
@@ -25,12 +25,11 @@ import java.util.concurrent.Callable;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import org.springframework.aop.framework.AopProxyUtils ;
import org.springframework.beans.factory.InitializingBean ;
import org.springframework.cache.Cache ;
import org.springframework.cache.CacheManager ;
import org.springframework.cache.KeyGenerator ;
import org.springframework.cache.support.DefaultKeyGenerator ;
import org.springframework.expression.EvaluationContext ;
import org.springframework.util.Assert ;
import org.springframework.util.ClassUtils ;
@ -57,6 +56,8 @@ import org.springframework.util.StringUtils;
@@ -57,6 +56,8 @@ import org.springframework.util.StringUtils;
* and < code > CacheDefinitionSource < / code > are serializable .
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 3 . 1
* /
public abstract class CacheAspectSupport implements InitializingBean {
@ -64,26 +65,82 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -64,26 +65,82 @@ public abstract class CacheAspectSupport implements InitializingBean {
private CacheManager cacheManager ;
private CacheOperationSource cacheDefini tionSource ;
private CacheOperationSource cacheOpera tionSource ;
private final ExpressionEvaluator evaluator = new ExpressionEvaluator ( ) ;
private KeyGenerator keyGenerator = new DefaultKeyGenerator ( ) ;
private volatile boolean initialized = false ;
private boolean initialized = false ;
/ * *
* Set the CacheManager that this cache aspect should delegate to .
* /
public void setCacheManager ( CacheManager cacheManager ) {
this . cacheManager = cacheManager ;
}
/ * *
* Return the CacheManager that this cache aspect delegates to .
* /
public CacheManager getCacheManager ( ) {
return this . cacheManager ;
}
/ * *
* Set multiple cache definition sources which are used to find the cache
* attributes . Will build a CompositeCachingDefinitionSource for the given sources .
* /
public void setCacheOperationSources ( CacheOperationSource . . . cacheDefinitionSources ) {
Assert . notEmpty ( cacheDefinitionSources ) ;
this . cacheOperationSource = ( cacheDefinitionSources . length > 1 ?
new CompositeCacheOperationSource ( cacheDefinitionSources ) : cacheDefinitionSources [ 0 ] ) ;
}
/ * *
* Set the CacheOperationSource for this cache aspect ,
* resolving applicable cache operations from annotations or the like .
* /
public void setCacheOperationSource ( CacheOperationSource cacheOperationSource ) {
this . cacheOperationSource = cacheOperationSource ;
}
/ * *
* Return the CacheOperationSource for this cache aspect .
* /
public CacheOperationSource getCacheOperationSource ( ) {
return this . cacheOperationSource ;
}
/ * *
* Set the KeyGenerator for this cache aspect .
* Default is { @link DefaultKeyGenerator } .
* /
public void setKeyGenerator ( KeyGenerator keyGenerator ) {
this . keyGenerator = keyGenerator ;
}
/ * *
* Return the KeyGenerator for this cache aspect ,
* /
public KeyGenerator getKeyGenerator ( ) {
return this . keyGenerator ;
}
public void afterPropertiesSet ( ) {
if ( this . cacheManager = = null ) {
throw new IllegalStateException ( "Setting the property 'cacheManager' is required" ) ;
throw new IllegalStateException ( "'cacheManager' is required" ) ;
}
if ( this . cacheDefinitionSource = = null ) {
if ( this . cacheOpera tionSource = = null ) {
throw new IllegalStateException ( "Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: "
+ "If there are no cacheable methods, then don't use a cache aspect." ) ;
}
initialized = true ;
this . initialized = true ;
}
/ * *
* Convenience method to return a String representation of this Method
* for use in logging . Can be overridden in subclasses to provide a
@ -98,62 +155,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -98,62 +155,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
return ClassUtils . getQualifiedMethodName ( specificMethod ) ;
}
public CacheManager getCacheManager ( ) {
return cacheManager ;
}
public void setCacheManager ( CacheManager cacheManager ) {
this . cacheManager = cacheManager ;
}
public CacheOperationSource getCacheDefinitionSource ( ) {
return cacheDefinitionSource ;
}
public KeyGenerator getKeyGenerator ( ) {
return keyGenerator ;
}
public void setKeyGenerator ( KeyGenerator keyGenerator ) {
this . keyGenerator = keyGenerator ;
}
/ * *
* Set multiple cache definition sources which are used to find the cache
* attributes . Will build a CompositeCachingDefinitionSource for the given sources .
* /
public void setCacheDefinitionSources ( CacheOperationSource . . . cacheDefinitionSources ) {
Assert . notEmpty ( cacheDefinitionSources ) ;
this . cacheDefinitionSource = ( cacheDefinitionSources . length > 1 ? new CompositeCacheOperationSource (
cacheDefinitionSources ) : cacheDefinitionSources [ 0 ] ) ;
}
protected Collection < Cache > getCaches ( CacheOperation operation ) {
Set < String > cacheNames = operation . getCacheNames ( ) ;
Collection < Cache > caches = new ArrayList < Cache > ( cacheNames . size ( ) ) ;
for ( String cacheName : cacheNames ) {
Cache cache = cacheManager . getCache ( cacheName ) ;
Cache cache = this . cacheManager . getCache ( cacheName ) ;
if ( cache = = null ) {
throw new IllegalArgumentException ( "Cannot find cache named [" + cacheName + "] for " + operation ) ;
}
caches . add ( cache ) ;
}
return caches ;
}
protected CacheOperationContext getOperationContext ( CacheOperation operation , Method method , Object [ ] args ,
Object target , Class < ? > targetClass ) {
return new CacheOperationContext ( operation , method , args , target , targetClass ) ;
}
protected Object execute ( Callable < Object > invocation , Object target , Method method , Object [ ] args ) throws Exception {
// check whether aspect is enabled
// to cope with cases where the AJ is pulled in automatically
if ( ! initialized ) {
if ( ! this . initialized ) {
return invocation . call ( ) ;
}
@ -161,15 +185,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -161,15 +185,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
// get backing class
Class < ? > targetClass = AopProxyUtils . ultimateTargetClass ( target ) ;
if ( targetClass = = null & & target ! = null ) {
targetClass = target . getClass ( ) ;
}
final CacheOperation cacheOp = getCacheDefini tionSource ( ) . getCacheOperation ( method , targetClass ) ;
final CacheOperation cacheOp = getCacheOpera tionSource ( ) . getCacheOperation ( method , targetClass ) ;
Object retVal = null ;
// analyze caching information
if ( cacheOp ! = null ) {
CacheOperationContext context = getOperationContext ( cacheOp , method , args , target , targetClass ) ;
@ -179,11 +201,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -179,11 +201,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
// check operation
if ( cacheOp instanceof CacheUpdateOperation ) {
Object key = context . generateKey ( ) ;
if ( log ) {
logger . trace ( "Computed cache key " + key + " for definition " + cacheOp ) ;
}
if ( key = = null ) {
throw new IllegalArgumentException (
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
@ -196,7 +216,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -196,7 +216,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
for ( Iterator < Cache > iterator = caches . iterator ( ) ; iterator . hasNext ( ) & & ! cacheHit ; ) {
Cache cache = iterator . next ( ) ;
Cache . ValueWrapper wrapper = cache . get ( key ) ;
if ( wrapper ! = null ) {
cacheHit = true ;
retVal = wrapper . get ( ) ;
@ -209,12 +228,12 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -209,12 +228,12 @@ public abstract class CacheAspectSupport implements InitializingBean {
+ method ) ;
}
retVal = invocation . call ( ) ;
// update all caches
for ( Cache cache : caches ) {
cache . put ( key , retVal ) ;
}
} else {
}
else {
if ( log ) {
logger . trace ( "Key " + key + " found in cache, returning value " + retVal ) ;
}
@ -234,10 +253,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -234,10 +253,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
if ( evictOp . isCacheWide ( ) ) {
cache . clear ( ) ;
if ( log ) {
logger . trace ( "Invalidating entire cache for definition " + cacheOp + " on method "
+ method ) ;
logger . trace ( "Invalidating entire cache for definition " + cacheOp +
" on method " + method ) ;
}
} else {
}
else {
// check key
if ( key = = null ) {
key = context . generateKey ( ) ;
@ -250,9 +270,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -250,9 +270,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
}
return retVal ;
} else {
}
else {
if ( log ) {
logger . trace ( "Cache condition failed on method " + method + " for definition " + cacheOp ) ;
}
@ -262,19 +282,22 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -262,19 +282,22 @@ public abstract class CacheAspectSupport implements InitializingBean {
return invocation . call ( ) ;
}
protected class CacheOperationContext {
private CacheOperation operation ;
private final CacheOperation operation ;
private final Collection < Cache > caches ;
private final Object target ;
private final Method method ;
private final Object [ ] args ;
// context passed around to avoid multiple creations
private final EvaluationContext evalContext ;
private final KeyGenerator keyGenerator = CacheAspectSupport . this . keyGenerator ;
public CacheOperationContext ( CacheOperation operation , Method method , Object [ ] args , Object target ,
Class < ? > targetClass ) {
this . operation = operation ;
@ -286,39 +309,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
@@ -286,39 +309,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
this . evalContext = evaluator . createEvaluationContext ( caches , method , args , target , targetClass ) ;
}
/ * *
* Evaluates the definition condition .
*
* @param operation
* @return
* /
protected boolean hasConditionPassed ( ) {
if ( StringUtils . hasText ( operation . getCondition ( ) ) ) {
return evaluator . condition ( operation . getCondition ( ) , method , evalContext ) ;
if ( StringUtils . hasText ( this . operation . getCondition ( ) ) ) {
return evaluator . condition ( this . operation . getCondition ( ) , this . method , this . evalContext ) ;
}
return true ;
}
/ * *
* Computes the key for the given caching definition .
*
* @param operation
* @param method
* method being invoked
* @param objects
* arguments passed during the method invocation
* Computes the key for the given caching operation .
* @return generated key ( null if none can be generated )
* /
protected Object generateKey ( ) {
if ( StringUtils . hasText ( operation . getKey ( ) ) ) {
return evaluator . key ( operation . getKey ( ) , method , evalContext ) ;
if ( StringUtils . hasText ( this . operation . getKey ( ) ) ) {
return evaluator . key ( this . operation . getKey ( ) , this . method , this . evalContext ) ;
}
return keyGenerator . extract ( target , method , args ) ;
return keyGenerator . extract ( this . target , this . method , this . args ) ;
}
protected Collection < Cache > getCaches ( ) {
return caches ;
return this . caches ;
}
}
}
}