Revised retrieval of cache strategy beans
Issue: SPR-12336
This commit is contained in:
parent
cfa3d358d5
commit
0e36402bd2
|
@ -28,6 +28,7 @@ import org.springframework.cache.interceptor.AbstractCacheInvoker;
|
||||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||||
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
|
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
|
||||||
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base interceptor for JSR-107 cache annotations.
|
* A base interceptor for JSR-107 cache annotations.
|
||||||
|
@ -41,12 +42,15 @@ abstract class AbstractCacheInterceptor<O extends AbstractJCacheOperation<A>, A
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
|
||||||
protected AbstractCacheInterceptor(CacheErrorHandler errorHandler) {
|
protected AbstractCacheInterceptor(CacheErrorHandler errorHandler) {
|
||||||
super(errorHandler);
|
super(errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Object invoke(CacheOperationInvocationContext<O> context,
|
|
||||||
CacheOperationInvoker invoker) throws Throwable;
|
protected abstract Object invoke(CacheOperationInvocationContext<O> context, CacheOperationInvoker invoker)
|
||||||
|
throws Throwable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the cache to use.
|
* Resolve the cache to use.
|
||||||
|
@ -68,15 +72,15 @@ abstract class AbstractCacheInterceptor<O extends AbstractJCacheOperation<A>, A
|
||||||
* @return the singe element or {@code null} if the collection is empty
|
* @return the singe element or {@code null} if the collection is empty
|
||||||
*/
|
*/
|
||||||
static Cache extractFrom(Collection<? extends Cache> caches) {
|
static Cache extractFrom(Collection<? extends Cache> caches) {
|
||||||
if (caches == null || caches.size() == 0) {
|
if (CollectionUtils.isEmpty(caches)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else if (caches.size() == 1) {
|
else if (caches.size() == 1) {
|
||||||
return caches.iterator().next();
|
return caches.iterator().next();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalStateException("Unsupported cache resolution result "
|
throw new IllegalStateException("Unsupported cache resolution result " + caches +
|
||||||
+ caches + " JSR-107 only supports a single cache.");
|
": JSR-107 only supports a single cache.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,35 +43,13 @@ import org.springframework.util.StringUtils;
|
||||||
*/
|
*/
|
||||||
public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJCacheOperationSource {
|
public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJCacheOperationSource {
|
||||||
|
|
||||||
/**
|
|
||||||
* Locate or create an instance of the specified {@code type}.
|
|
||||||
* @param type the type of the bean to manage
|
|
||||||
* @return the required bean
|
|
||||||
*/
|
|
||||||
protected abstract <T> T getBean(Class<T> type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the default {@link CacheResolver} if none is set.
|
|
||||||
*/
|
|
||||||
protected abstract CacheResolver getDefaultCacheResolver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the default exception {@link CacheResolver} if none is set.
|
|
||||||
*/
|
|
||||||
protected abstract CacheResolver getDefaultExceptionCacheResolver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the default {@link KeyGenerator} if none is set.
|
|
||||||
*/
|
|
||||||
protected abstract KeyGenerator getDefaultKeyGenerator();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JCacheOperation<?> findCacheOperation(Method method, Class<?> targetType) {
|
protected JCacheOperation<?> findCacheOperation(Method method, Class<?> targetType) {
|
||||||
CacheResult cacheResult = method.getAnnotation(CacheResult.class);
|
CacheResult cacheResult = method.getAnnotation(CacheResult.class);
|
||||||
CachePut cachePut = method.getAnnotation(CachePut.class);
|
CachePut cachePut = method.getAnnotation(CachePut.class);
|
||||||
CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
|
CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
|
||||||
CacheRemoveAll cacheRemoveAll = method.getAnnotation(CacheRemoveAll.class);
|
CacheRemoveAll cacheRemoveAll = method.getAnnotation(CacheRemoveAll.class);
|
||||||
|
|
||||||
int found = countNonNull(cacheResult, cachePut, cacheRemove, cacheRemoveAll);
|
int found = countNonNull(cacheResult, cachePut, cacheRemove, cacheRemoveAll);
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -79,8 +57,8 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
if (found > 1) {
|
if (found > 1) {
|
||||||
throw new IllegalStateException("More than one cache annotation found on '" + method + "'");
|
throw new IllegalStateException("More than one cache annotation found on '" + method + "'");
|
||||||
}
|
}
|
||||||
CacheDefaults defaults = getCacheDefaults(method, targetType);
|
|
||||||
|
|
||||||
|
CacheDefaults defaults = getCacheDefaults(method, targetType);
|
||||||
if (cacheResult != null) {
|
if (cacheResult != null) {
|
||||||
return createCacheResultOperation(method, defaults, cacheResult);
|
return createCacheResultOperation(method, defaults, cacheResult);
|
||||||
}
|
}
|
||||||
|
@ -103,9 +81,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
return targetType.getAnnotation(CacheDefaults.class);
|
return targetType.getAnnotation(CacheDefaults.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults, CacheResult ann) {
|
||||||
protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults,
|
|
||||||
CacheResult ann) {
|
|
||||||
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
||||||
CacheResolverFactory cacheResolverFactory =
|
CacheResolverFactory cacheResolverFactory =
|
||||||
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
||||||
|
@ -123,49 +99,39 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
return new CacheResultOperation(methodDetails, cacheResolver, keyGenerator, exceptionCacheResolver);
|
return new CacheResultOperation(methodDetails, cacheResolver, keyGenerator, exceptionCacheResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults,
|
protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults, CachePut ann) {
|
||||||
CachePut ann) {
|
|
||||||
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
||||||
CacheResolverFactory cacheResolverFactory =
|
CacheResolverFactory cacheResolverFactory =
|
||||||
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
||||||
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
|
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
|
||||||
|
|
||||||
CacheMethodDetails<CachePut> methodDetails = createMethodDetails(method, ann, cacheName);
|
CacheMethodDetails<CachePut> methodDetails = createMethodDetails(method, ann, cacheName);
|
||||||
|
|
||||||
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
||||||
|
|
||||||
return new CachePutOperation(methodDetails, cacheResolver, keyGenerator);
|
return new CachePutOperation(methodDetails, cacheResolver, keyGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults,
|
protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults, CacheRemove ann) {
|
||||||
CacheRemove ann) {
|
|
||||||
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
||||||
CacheResolverFactory cacheResolverFactory =
|
CacheResolverFactory cacheResolverFactory =
|
||||||
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
||||||
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
|
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
|
||||||
|
|
||||||
CacheMethodDetails<CacheRemove> methodDetails = createMethodDetails(method, ann, cacheName);
|
CacheMethodDetails<CacheRemove> methodDetails = createMethodDetails(method, ann, cacheName);
|
||||||
|
|
||||||
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
||||||
|
|
||||||
return new CacheRemoveOperation(methodDetails, cacheResolver, keyGenerator);
|
return new CacheRemoveOperation(methodDetails, cacheResolver, keyGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults,
|
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults, CacheRemoveAll ann) {
|
||||||
CacheRemoveAll ann) {
|
|
||||||
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
String cacheName = determineCacheName(method, defaults, ann.cacheName());
|
||||||
CacheResolverFactory cacheResolverFactory =
|
CacheResolverFactory cacheResolverFactory =
|
||||||
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
|
||||||
|
|
||||||
CacheMethodDetails<CacheRemoveAll> methodDetails = createMethodDetails(method, ann, cacheName);
|
CacheMethodDetails<CacheRemoveAll> methodDetails = createMethodDetails(method, ann, cacheName);
|
||||||
|
|
||||||
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
|
||||||
|
|
||||||
return new CacheRemoveAllOperation(methodDetails, cacheResolver);
|
return new CacheRemoveAllOperation(methodDetails, cacheResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <A extends Annotation> CacheMethodDetails<A> createMethodDetails(
|
private <A extends Annotation> CacheMethodDetails<A> createMethodDetails(Method method, A annotation, String cacheName) {
|
||||||
Method method, A annotation, String cacheName) {
|
|
||||||
return new DefaultCacheMethodDetails<A>(method, annotation, cacheName);
|
return new DefaultCacheMethodDetails<A>(method, annotation, cacheName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +147,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
|
|
||||||
protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory,
|
protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory,
|
||||||
CacheMethodDetails<CacheResult> details) {
|
CacheMethodDetails<CacheResult> details) {
|
||||||
|
|
||||||
if (factory != null) {
|
if (factory != null) {
|
||||||
javax.cache.annotation.CacheResolver cacheResolver = factory.getExceptionCacheResolver(details);
|
javax.cache.annotation.CacheResolver cacheResolver = factory.getExceptionCacheResolver(details);
|
||||||
return new CacheResolverAdapter(cacheResolver);
|
return new CacheResolverAdapter(cacheResolver);
|
||||||
|
@ -192,6 +159,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
|
|
||||||
protected CacheResolverFactory determineCacheResolverFactory(CacheDefaults defaults,
|
protected CacheResolverFactory determineCacheResolverFactory(CacheDefaults defaults,
|
||||||
Class<? extends CacheResolverFactory> candidate) {
|
Class<? extends CacheResolverFactory> candidate) {
|
||||||
|
|
||||||
if (!CacheResolverFactory.class.equals(candidate)) {
|
if (!CacheResolverFactory.class.equals(candidate)) {
|
||||||
return getBean(candidate);
|
return getBean(candidate);
|
||||||
}
|
}
|
||||||
|
@ -203,8 +171,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected KeyGenerator determineKeyGenerator(CacheDefaults defaults,
|
protected KeyGenerator determineKeyGenerator(CacheDefaults defaults, Class<? extends CacheKeyGenerator> candidate) {
|
||||||
Class<? extends CacheKeyGenerator> candidate) {
|
|
||||||
if (!CacheKeyGenerator.class.equals(candidate)) {
|
if (!CacheKeyGenerator.class.equals(candidate)) {
|
||||||
return new KeyGeneratorAdapter(this, getBean(candidate));
|
return new KeyGeneratorAdapter(this, getBean(candidate));
|
||||||
}
|
}
|
||||||
|
@ -233,28 +200,48 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
|
||||||
*/
|
*/
|
||||||
protected String generateDefaultCacheName(Method method) {
|
protected String generateDefaultCacheName(Method method) {
|
||||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||||
List<String> parameters = new ArrayList<String>();
|
List<String> parameters = new ArrayList<String>(parameterTypes.length);
|
||||||
for (Class<?> parameterType : parameterTypes) {
|
for (Class<?> parameterType : parameterTypes) {
|
||||||
parameters.add(parameterType.getName());
|
parameters.add(parameterType.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder(method.getDeclaringClass().getName());
|
||||||
sb.append(method.getDeclaringClass().getName())
|
sb.append(".").append(method.getName());
|
||||||
.append(".")
|
sb.append("(").append(StringUtils.collectionToCommaDelimitedString(parameters)).append(")");
|
||||||
.append(method.getName())
|
|
||||||
.append("(")
|
|
||||||
.append(StringUtils.collectionToCommaDelimitedString(parameters))
|
|
||||||
.append(")");
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countNonNull(Object... instances) {
|
private int countNonNull(Object... instances) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (Object o : instances) {
|
for (Object instance : instances) {
|
||||||
if (o != null) {
|
if (instance != null) {
|
||||||
result += 1;
|
result += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate or create an instance of the specified cache strategy {@code type}.
|
||||||
|
* @param type the type of the bean to manage
|
||||||
|
* @return the required bean
|
||||||
|
*/
|
||||||
|
protected abstract <T> T getBean(Class<T> type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the default {@link CacheResolver} if none is set.
|
||||||
|
*/
|
||||||
|
protected abstract CacheResolver getDefaultCacheResolver();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the default exception {@link CacheResolver} if none is set.
|
||||||
|
*/
|
||||||
|
protected abstract CacheResolver getDefaultExceptionCacheResolver();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the default {@link KeyGenerator} if none is set.
|
||||||
|
*/
|
||||||
|
protected abstract KeyGenerator getDefaultKeyGenerator();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,10 @@
|
||||||
|
|
||||||
package org.springframework.cache.jcache.interceptor;
|
package org.springframework.cache.jcache.interceptor;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.interceptor.CacheResolver;
|
import org.springframework.cache.interceptor.CacheResolver;
|
||||||
|
@ -40,7 +39,7 @@ import org.springframework.util.Assert;
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource
|
public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource
|
||||||
implements InitializingBean, SmartInitializingSingleton, ApplicationContextAware {
|
implements ApplicationContextAware, InitializingBean, SmartInitializingSingleton {
|
||||||
|
|
||||||
private CacheManager cacheManager;
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
|
@ -54,6 +53,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||||
|
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the default {@link CacheManager} to use to lookup cache by name. Only mandatory
|
* Set the default {@link CacheManager} to use to lookup cache by name. Only mandatory
|
||||||
* if the {@linkplain CacheResolver cache resolvers} have not been set.
|
* if the {@linkplain CacheResolver cache resolvers} have not been set.
|
||||||
|
@ -104,24 +104,33 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
this.adaptedKeyGenerator = new KeyGeneratorAdapter(this, this.keyGenerator);
|
this.adaptedKeyGenerator = new KeyGeneratorAdapter(this, this.keyGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSingletonsInstantiated() { // Make sure those are initialized on startup
|
public void afterSingletonsInstantiated() {
|
||||||
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized.");
|
// Make sure those are initialized on startup...
|
||||||
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized.");
|
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
|
||||||
|
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> T getBean(Class<T> type) {
|
protected <T> T getBean(Class<T> type) {
|
||||||
Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, type);
|
try {
|
||||||
if (map.size() == 1) {
|
return this.applicationContext.getBean(type);
|
||||||
return map.values().iterator().next();
|
|
||||||
}
|
}
|
||||||
else {
|
catch (NoUniqueBeanDefinitionException ex) {
|
||||||
|
throw new IllegalStateException("No unique [" + type.getName() + "] bean found in application context - " +
|
||||||
|
"mark one as primary, or declare a more specific implementation type for your cache", ex);
|
||||||
|
}
|
||||||
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("No bean of type [" + type.getName() + "] found in application context", ex);
|
||||||
|
}
|
||||||
return BeanUtils.instantiateClass(type);
|
return BeanUtils.instantiateClass(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,11 +158,16 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||||
|
|
||||||
private CacheManager getCacheManager() {
|
private CacheManager getCacheManager() {
|
||||||
if (this.cacheManager == null) {
|
if (this.cacheManager == null) {
|
||||||
this.cacheManager = this.applicationContext.getBean(CacheManager.class);
|
try {
|
||||||
if (this.cacheManager == null) {
|
this.cacheManager = this.applicationContext.getBean(CacheManager.class);
|
||||||
throw new IllegalStateException("No bean of type CacheManager could be found. " +
|
}
|
||||||
"Register a CacheManager bean or remove the @EnableCaching annotation " +
|
catch (NoUniqueBeanDefinitionException ex) {
|
||||||
"from your configuration.");
|
throw new IllegalStateException("No unique bean of type CacheManager found. "+
|
||||||
|
"Mark one as primary or declare a specific CacheManager to use.");
|
||||||
|
}
|
||||||
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
|
throw new IllegalStateException("No bean of type CacheManager found. Register a CacheManager "+
|
||||||
|
"bean or remove the @EnableCaching annotation from your configuration.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.cacheManager;
|
return this.cacheManager;
|
||||||
|
|
|
@ -78,9 +78,9 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSource' property is required: " +
|
Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSource' property is required: " +
|
||||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||||
Assert.state(this.getErrorHandler() != null, "The 'errorHandler' is required.");
|
Assert.state(getErrorHandler() != null, "The 'errorHandler' is required");
|
||||||
|
|
||||||
this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler());
|
this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler());
|
||||||
this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler());
|
this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler());
|
||||||
|
@ -92,8 +92,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||||
|
|
||||||
|
|
||||||
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
|
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
|
||||||
// check whether aspect is enabled
|
// Check whether aspect is enabled to cope with cases where the AJ is pulled in automatically
|
||||||
// to cope with cases where the AJ is pulled in automatically
|
|
||||||
if (this.initialized) {
|
if (this.initialized) {
|
||||||
Class<?> targetClass = getTargetClass(target);
|
Class<?> targetClass = getTargetClass(target);
|
||||||
JCacheOperation<?> operation = getCacheOperationSource().getCacheOperation(method, targetClass);
|
JCacheOperation<?> operation = getCacheOperationSource().getCacheOperation(method, targetClass);
|
||||||
|
@ -108,9 +107,9 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private CacheOperationInvocationContext<?> createCacheOperationInvocationContext(Object target,
|
private CacheOperationInvocationContext<?> createCacheOperationInvocationContext(
|
||||||
Object[] args,
|
Object target, Object[] args, JCacheOperation<?> operation) {
|
||||||
JCacheOperation<?> operation) {
|
|
||||||
return new DefaultCacheInvocationContext<Annotation>(
|
return new DefaultCacheInvocationContext<Annotation>(
|
||||||
(JCacheOperation<Annotation>) operation, target, args);
|
(JCacheOperation<Annotation>) operation, target, args);
|
||||||
}
|
}
|
||||||
|
@ -124,12 +123,10 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Object execute(CacheOperationInvocationContext<?> context,
|
private Object execute(CacheOperationInvocationContext<?> context, CacheOperationInvoker invoker) {
|
||||||
CacheOperationInvoker invoker) {
|
|
||||||
|
|
||||||
CacheOperationInvoker adapter = new CacheOperationInvokerAdapter(invoker);
|
CacheOperationInvoker adapter = new CacheOperationInvokerAdapter(invoker);
|
||||||
|
|
||||||
BasicOperation operation = context.getOperation();
|
BasicOperation operation = context.getOperation();
|
||||||
|
|
||||||
if (operation instanceof CacheResultOperation) {
|
if (operation instanceof CacheResultOperation) {
|
||||||
return cacheResultInterceptor.invoke(
|
return cacheResultInterceptor.invoke(
|
||||||
(CacheOperationInvocationContext<CacheResultOperation>) context, adapter);
|
(CacheOperationInvocationContext<CacheResultOperation>) context, adapter);
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
||||||
import org.springframework.cache.interceptor.CacheResolver;
|
import org.springframework.cache.interceptor.CacheResolver;
|
||||||
|
@ -51,11 +50,11 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||||
try {
|
try {
|
||||||
interceptor.execute(dummyInvoker, service, m, new Object[] {"myId"});
|
interceptor.execute(dummyInvoker, service, m, new Object[] {"myId"});
|
||||||
}
|
}
|
||||||
catch (IllegalStateException e) {
|
catch (IllegalStateException ex) {
|
||||||
assertTrue(e.getMessage().contains("JSR-107 only supports a single cache."));
|
assertTrue(ex.getMessage().contains("JSR-107 only supports a single cache"));
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable ex) {
|
||||||
fail("Unexpected: " + t);
|
fail("Unexpected: " + ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,17 +70,17 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||||
try {
|
try {
|
||||||
interceptor.execute(dummyInvoker, service, m, new Object[] {"myId"});
|
interceptor.execute(dummyInvoker, service, m, new Object[] {"myId"});
|
||||||
}
|
}
|
||||||
catch (IllegalStateException e) {
|
catch (IllegalStateException ex) {
|
||||||
assertTrue(e.getMessage().contains("Cache could not have been resolved for"));
|
assertTrue(ex.getMessage().contains("Cache could not have been resolved for"));
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable ex) {
|
||||||
fail("Unexpected: " + t);
|
fail("Unexpected: " + ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cacheManagerMandatoryIfCacheResolverNotSetSet() {
|
public void cacheManagerMandatoryIfCacheResolverNotSet() {
|
||||||
thrown.expect(NoSuchBeanDefinitionException.class);
|
thrown.expect(IllegalStateException.class);
|
||||||
createOperationSource(null, null, null, defaultKeyGenerator);
|
createOperationSource(null, null, null, defaultKeyGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,23 +92,21 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||||
@Test
|
@Test
|
||||||
public void cacheResultReturnsProperType() throws Throwable {
|
public void cacheResultReturnsProperType() throws Throwable {
|
||||||
JCacheInterceptor interceptor = createInterceptor(createOperationSource(
|
JCacheInterceptor interceptor = createInterceptor(createOperationSource(
|
||||||
cacheManager, defaultCacheResolver,
|
cacheManager, defaultCacheResolver, defaultExceptionCacheResolver, defaultKeyGenerator));
|
||||||
defaultExceptionCacheResolver, defaultKeyGenerator));
|
|
||||||
|
|
||||||
AnnotatedJCacheableService service = new AnnotatedJCacheableService(cacheManager.getCache("default"));
|
AnnotatedJCacheableService service = new AnnotatedJCacheableService(cacheManager.getCache("default"));
|
||||||
Method m = ReflectionUtils.findMethod(AnnotatedJCacheableService.class, "cache", String.class);
|
Method method = ReflectionUtils.findMethod(AnnotatedJCacheableService.class, "cache", String.class);
|
||||||
|
|
||||||
CacheOperationInvoker invoker = new DummyInvoker(0L);
|
CacheOperationInvoker invoker = new DummyInvoker(0L);
|
||||||
Object execute = interceptor.execute(invoker, service, m, new Object[] {"myId"});
|
Object execute = interceptor.execute(invoker, service, method, new Object[] {"myId"});
|
||||||
assertNotNull("result cannot be null.", execute);
|
assertNotNull("result cannot be null.", execute);
|
||||||
assertEquals("Wrong result type", Long.class, execute.getClass());
|
assertEquals("Wrong result type", Long.class, execute.getClass());
|
||||||
assertEquals("Wrong result", 0L, execute);
|
assertEquals("Wrong result", 0L, execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JCacheOperationSource createOperationSource(CacheManager cacheManager,
|
protected JCacheOperationSource createOperationSource(CacheManager cacheManager,
|
||||||
CacheResolver cacheResolver,
|
CacheResolver cacheResolver, CacheResolver exceptionCacheResolver, KeyGenerator keyGenerator) {
|
||||||
CacheResolver exceptionCacheResolver,
|
|
||||||
KeyGenerator keyGenerator) {
|
|
||||||
DefaultJCacheOperationSource source = new DefaultJCacheOperationSource();
|
DefaultJCacheOperationSource source = new DefaultJCacheOperationSource();
|
||||||
source.setApplicationContext(new StaticApplicationContext());
|
source.setApplicationContext(new StaticApplicationContext());
|
||||||
source.setCacheManager(cacheManager);
|
source.setCacheManager(cacheManager);
|
||||||
|
@ -129,6 +126,7 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class DummyInvoker implements CacheOperationInvoker {
|
private static class DummyInvoker implements CacheOperationInvoker {
|
||||||
|
|
||||||
private final Object result;
|
private final Object result;
|
||||||
|
|
|
@ -30,6 +30,8 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.aop.framework.AopProxyUtils;
|
import org.springframework.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
|
@ -98,9 +100,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set one or more cache operation sources which are used to find the cache
|
* Set one or more cache operation sources which are used to find the cache
|
||||||
* attributes. If more than one source is provided, they will be aggregated using a
|
* attributes. If more than one source is provided, they will be aggregated
|
||||||
* {@link CompositeCacheOperationSource}.
|
* using a {@link CompositeCacheOperationSource}.
|
||||||
* @param cacheOperationSources must not be {@code null}
|
|
||||||
*/
|
*/
|
||||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||||
Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
|
Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
|
||||||
|
@ -132,9 +133,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link CacheManager} to use to create a default {@link CacheResolver}. Replace
|
* Set the {@link CacheManager} to use to create a default {@link CacheResolver}.
|
||||||
* the current {@link CacheResolver}, if any.
|
* Replace the current {@link CacheResolver}, if any.
|
||||||
*
|
|
||||||
* @see #setCacheResolver(CacheResolver)
|
* @see #setCacheResolver(CacheResolver)
|
||||||
* @see SimpleCacheResolver
|
* @see SimpleCacheResolver
|
||||||
*/
|
*/
|
||||||
|
@ -151,7 +151,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
* @see SimpleCacheResolver
|
* @see SimpleCacheResolver
|
||||||
*/
|
*/
|
||||||
public void setCacheResolver(CacheResolver cacheResolver) {
|
public void setCacheResolver(CacheResolver cacheResolver) {
|
||||||
Assert.notNull(cacheResolver);
|
Assert.notNull(cacheResolver, "CacheResolver must not be null");
|
||||||
this.cacheResolver = cacheResolver;
|
this.cacheResolver = cacheResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
* Return the default {@link CacheResolver} that this cache aspect delegates to.
|
* Return the default {@link CacheResolver} that this cache aspect delegates to.
|
||||||
*/
|
*/
|
||||||
public CacheResolver getCacheResolver() {
|
public CacheResolver getCacheResolver() {
|
||||||
return cacheResolver;
|
return this.cacheResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,28 +167,33 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSources' property is required: " +
|
Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSources' property is required: " +
|
||||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||||
Assert.state(this.getErrorHandler() != null, "The 'errorHandler' is required.");
|
Assert.state(getErrorHandler() != null, "The 'errorHandler' property is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSingletonsInstantiated() {
|
public void afterSingletonsInstantiated() {
|
||||||
if (getCacheResolver() == null) { // lazy initialize cache resolver
|
if (getCacheResolver() == null) {
|
||||||
CacheManager cacheManager = this.applicationContext.getBean(CacheManager.class);
|
// Lazily initialize cache resolver via default cache manager...
|
||||||
if (cacheManager == null) {
|
try {
|
||||||
throw new IllegalStateException("No bean of type CacheManager could be found. " +
|
setCacheManager(this.applicationContext.getBean(CacheManager.class));
|
||||||
"Register a CacheManager bean or remove the @EnableCaching annotation " +
|
}
|
||||||
"from your configuration.");
|
catch (NoUniqueBeanDefinitionException ex) {
|
||||||
|
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
|
||||||
|
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
|
||||||
|
}
|
||||||
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
|
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
|
||||||
|
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.");
|
||||||
}
|
}
|
||||||
setCacheManager(cacheManager);
|
|
||||||
}
|
}
|
||||||
Assert.state(this.cacheResolver != null, "'cacheResolver' is required. Either set the cache resolver " +
|
|
||||||
"to use or set the cache manager to create a default cache resolver based on it.");
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to return a String representation of this Method
|
* Convenience method to return a String representation of this Method
|
||||||
* for use in logging. Can be overridden in subclasses to provide a
|
* for use in logging. Can be overridden in subclasses to provide a
|
||||||
|
@ -203,19 +208,20 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection<? extends Cache> getCaches(CacheOperationInvocationContext<CacheOperation> context,
|
protected Collection<? extends Cache> getCaches(
|
||||||
CacheResolver cacheResolver) {
|
CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {
|
||||||
|
|
||||||
Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
|
Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
|
||||||
if (caches.isEmpty()) {
|
if (caches.isEmpty()) {
|
||||||
throw new IllegalStateException("No cache could be resolved for '" + context.getOperation()
|
throw new IllegalStateException("No cache could be resolved for '" +
|
||||||
+ "' using resolver '" + cacheResolver
|
context.getOperation() + "' using resolver '" + cacheResolver +
|
||||||
+ "'. At least one cache should be provided per cache operation.");
|
"'. At least one cache should be provided per cache operation.");
|
||||||
}
|
}
|
||||||
return caches;
|
return caches;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
protected CacheOperationContext getOperationContext(
|
||||||
Object target, Class<?> targetClass) {
|
CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||||
|
|
||||||
CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
|
CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
|
||||||
return new CacheOperationContext(metadata, args, target);
|
return new CacheOperationContext(metadata, args, target);
|
||||||
|
@ -230,10 +236,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
* @param targetClass the target type
|
* @param targetClass the target type
|
||||||
* @return the resolved metadata for the operation
|
* @return the resolved metadata for the operation
|
||||||
*/
|
*/
|
||||||
protected CacheOperationMetadata getCacheOperationMetadata(CacheOperation operation,
|
protected CacheOperationMetadata getCacheOperationMetadata(
|
||||||
Method method, Class<?> targetClass) {
|
CacheOperation operation, Method method, Class<?> targetClass) {
|
||||||
final CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
|
|
||||||
CacheOperationMetadata metadata = metadataCache.get(cacheKey);
|
CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
|
||||||
|
CacheOperationMetadata metadata = this.metadataCache.get(cacheKey);
|
||||||
if (metadata == null) {
|
if (metadata == null) {
|
||||||
KeyGenerator operationKeyGenerator;
|
KeyGenerator operationKeyGenerator;
|
||||||
if (StringUtils.hasText(operation.getKeyGenerator())) {
|
if (StringUtils.hasText(operation.getKeyGenerator())) {
|
||||||
|
@ -255,7 +262,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
metadata = new CacheOperationMetadata(operation, method, targetClass,
|
metadata = new CacheOperationMetadata(operation, method, targetClass,
|
||||||
operationKeyGenerator, operationCacheResolver);
|
operationKeyGenerator, operationCacheResolver);
|
||||||
metadataCache.put(cacheKey, metadata);
|
this.metadataCache.put(cacheKey, metadata);
|
||||||
}
|
}
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +270,6 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
/**
|
/**
|
||||||
* Return a bean with the specified name and type. Used to resolve services that
|
* Return a bean with the specified name and type. Used to resolve services that
|
||||||
* are referenced by name in a {@link CacheOperation}.
|
* are referenced by name in a {@link CacheOperation}.
|
||||||
*
|
|
||||||
* @param beanName the name of the bean, as defined by the operation
|
* @param beanName the name of the bean, as defined by the operation
|
||||||
* @param expectedType type type for the bean
|
* @param expectedType type type for the bean
|
||||||
* @return the bean matching that name
|
* @return the bean matching that name
|
||||||
|
@ -273,15 +279,14 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
* @see CacheOperation#cacheResolver
|
* @see CacheOperation#cacheResolver
|
||||||
*/
|
*/
|
||||||
protected <T> T getBean(String beanName, Class<T> expectedType) {
|
protected <T> T getBean(String beanName, Class<T> expectedType) {
|
||||||
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
|
||||||
applicationContext, expectedType, beanName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the cached metadata.
|
* Clear the cached metadata.
|
||||||
*/
|
*/
|
||||||
protected void clearMetadataCache() {
|
protected void clearMetadataCache() {
|
||||||
metadataCache.clear();
|
this.metadataCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
|
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
|
||||||
|
@ -486,8 +491,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
private final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts =
|
private final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts =
|
||||||
new LinkedMultiValueMap<Class<? extends CacheOperation>, CacheOperationContext>();
|
new LinkedMultiValueMap<Class<? extends CacheOperation>, CacheOperationContext>();
|
||||||
|
|
||||||
public CacheOperationContexts(Collection<? extends CacheOperation> operations,
|
public CacheOperationContexts(Collection<? extends CacheOperation> operations, Method method,
|
||||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
Object[] args, Object target, Class<?> targetClass) {
|
||||||
|
|
||||||
for (CacheOperation operation : operations) {
|
for (CacheOperation operation : operations) {
|
||||||
this.contexts.add(operation.getClass(), getOperationContext(operation, method, args, target, targetClass));
|
this.contexts.add(operation.getClass(), getOperationContext(operation, method, args, target, targetClass));
|
||||||
|
@ -508,14 +513,18 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
protected static class CacheOperationMetadata {
|
protected static class CacheOperationMetadata {
|
||||||
|
|
||||||
private final CacheOperation operation;
|
private final CacheOperation operation;
|
||||||
|
|
||||||
private final Method method;
|
private final Method method;
|
||||||
|
|
||||||
private final Class<?> targetClass;
|
private final Class<?> targetClass;
|
||||||
|
|
||||||
private final KeyGenerator keyGenerator;
|
private final KeyGenerator keyGenerator;
|
||||||
|
|
||||||
private final CacheResolver cacheResolver;
|
private final CacheResolver cacheResolver;
|
||||||
|
|
||||||
public CacheOperationMetadata(CacheOperation operation, Method method,
|
public CacheOperationMetadata(CacheOperation operation, Method method, Class<?> targetClass,
|
||||||
Class<?> targetClass, KeyGenerator keyGenerator,
|
KeyGenerator keyGenerator, CacheResolver cacheResolver) {
|
||||||
CacheResolver cacheResolver) {
|
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.targetClass = targetClass;
|
this.targetClass = targetClass;
|
||||||
|
@ -524,6 +533,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
|
protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
|
||||||
|
|
||||||
private final CacheOperationMetadata metadata;
|
private final CacheOperationMetadata metadata;
|
||||||
|
@ -536,8 +546,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
|
|
||||||
private final MethodCacheKey methodCacheKey;
|
private final MethodCacheKey methodCacheKey;
|
||||||
|
|
||||||
public CacheOperationContext(CacheOperationMetadata metadata,
|
public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
|
||||||
Object[] args, Object target) {
|
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.args = extractArgs(metadata.method, args);
|
this.args = extractArgs(metadata.method, args);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
@ -547,22 +556,22 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation() {
|
public CacheOperation getOperation() {
|
||||||
return metadata.operation;
|
return this.metadata.operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getTarget() {
|
public Object getTarget() {
|
||||||
return target;
|
return this.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Method getMethod() {
|
public Method getMethod() {
|
||||||
return metadata.method;
|
return this.metadata.method;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getArgs() {
|
public Object[] getArgs() {
|
||||||
return args;
|
return this.args;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object[] extractArgs(Method method, Object[] args) {
|
private Object[] extractArgs(Method method, Object[] args) {
|
||||||
|
@ -579,7 +588,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
protected boolean isConditionPassing(Object result) {
|
protected boolean isConditionPassing(Object result) {
|
||||||
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
|
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
|
||||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||||
return evaluator.condition(this.metadata.operation.getCondition(), this.methodCacheKey, evaluationContext);
|
return evaluator.condition(this.metadata.operation.getCondition(),
|
||||||
|
this.methodCacheKey, evaluationContext);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -600,15 +610,15 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the key for the given caching operation.
|
* Compute the key for the given caching operation.
|
||||||
* @return generated key (null if none can be generated)
|
* @return the generated key, or {@code null} if none can be generated
|
||||||
*/
|
*/
|
||||||
protected Object generateKey(Object result) {
|
protected Object generateKey(Object result) {
|
||||||
if (StringUtils.hasText(this.metadata.operation.getKey())) {
|
if (StringUtils.hasText(this.metadata.operation.getKey())) {
|
||||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||||
return evaluator.key(this.metadata.operation.getKey(), this.methodCacheKey, evaluationContext);
|
return evaluator.key(this.metadata.operation.getKey(), this.methodCacheKey, evaluationContext);
|
||||||
}
|
}
|
||||||
return metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
|
return this.metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EvaluationContext createEvaluationContext(Object result) {
|
private EvaluationContext createEvaluationContext(Object result) {
|
||||||
|
@ -642,9 +652,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class CacheOperationCacheKey {
|
private static class CacheOperationCacheKey {
|
||||||
|
|
||||||
private final CacheOperation cacheOperation;
|
private final CacheOperation cacheOperation;
|
||||||
|
|
||||||
private final MethodCacheKey methodCacheKey;
|
private final MethodCacheKey methodCacheKey;
|
||||||
|
|
||||||
private CacheOperationCacheKey(CacheOperation cacheOperation, Method method, Class<?> targetClass) {
|
private CacheOperationCacheKey(CacheOperation cacheOperation, Method method, Class<?> targetClass) {
|
||||||
|
@ -653,20 +665,21 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object other) {
|
||||||
if (this == o) return true;
|
if (this == other) {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
return true;
|
||||||
|
}
|
||||||
CacheOperationCacheKey that = (CacheOperationCacheKey) o;
|
if (!(other instanceof CacheOperationCacheKey)) {
|
||||||
return cacheOperation.equals(that.cacheOperation)
|
return false;
|
||||||
&& methodCacheKey.equals(that.methodCacheKey);
|
}
|
||||||
|
CacheOperationCacheKey otherKey = (CacheOperationCacheKey) other;
|
||||||
|
return (this.cacheOperation.equals(otherKey.cacheOperation) &&
|
||||||
|
this.methodCacheKey.equals(otherKey.methodCacheKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = cacheOperation.hashCode();
|
return (this.cacheOperation.hashCode() * 31 + this.methodCacheKey.hashCode());
|
||||||
result = 31 * result + methodCacheKey.hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ package org.springframework.cache.config;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.CacheTestUtils;
|
import org.springframework.cache.CacheTestUtils;
|
||||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||||
|
@ -75,13 +73,14 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=NoUniqueBeanDefinitionException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void multipleCacheManagerBeans() throws Throwable {
|
public void multipleCacheManagerBeans() throws Throwable {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.register(MultiCacheManagerConfig.class);
|
ctx.register(MultiCacheManagerConfig.class);
|
||||||
try {
|
try {
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
} catch (BeanCreationException ex) {
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
Throwable root = ex.getRootCause();
|
Throwable root = ex.getRootCause();
|
||||||
assertTrue(root.getMessage().contains("beans of type CacheManager"));
|
assertTrue(root.getMessage().contains("beans of type CacheManager"));
|
||||||
throw root;
|
throw root;
|
||||||
|
@ -95,26 +94,28 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
ctx.refresh(); // does not throw
|
ctx.refresh(); // does not throw
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void multipleCachingConfigurers() throws Throwable {
|
public void multipleCachingConfigurers() throws Throwable {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.register(MultiCacheManagerConfigurer.class, EnableCachingConfig.class);
|
ctx.register(MultiCacheManagerConfigurer.class, EnableCachingConfig.class);
|
||||||
try {
|
try {
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
} catch (BeanCreationException ex) {
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
Throwable root = ex.getRootCause();
|
Throwable root = ex.getRootCause();
|
||||||
assertTrue(root.getMessage().contains("implementations of CachingConfigurer"));
|
assertTrue(root.getMessage().contains("implementations of CachingConfigurer"));
|
||||||
throw root;
|
throw root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=NoSuchBeanDefinitionException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void noCacheManagerBeans() throws Throwable {
|
public void noCacheManagerBeans() throws Throwable {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.register(EmptyConfig.class);
|
ctx.register(EmptyConfig.class);
|
||||||
try {
|
try {
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
} catch (BeanCreationException ex) {
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
Throwable root = ex.getRootCause();
|
Throwable root = ex.getRootCause();
|
||||||
assertTrue(root.getMessage().contains("No bean of type CacheManager"));
|
assertTrue(root.getMessage().contains("No bean of type CacheManager"));
|
||||||
throw root;
|
throw root;
|
||||||
|
@ -149,6 +150,7 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class EnableCachingConfig extends CachingConfigurerSupport {
|
static class EnableCachingConfig extends CachingConfigurerSupport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cacheManager() {
|
public CacheManager cacheManager() {
|
||||||
|
@ -198,39 +200,56 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class SingleCacheManagerConfig {
|
static class SingleCacheManagerConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cm1() { return new NoOpCacheManager(); }
|
public CacheManager cm1() {
|
||||||
|
return new NoOpCacheManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class MultiCacheManagerConfig {
|
static class MultiCacheManagerConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cm1() { return new NoOpCacheManager(); }
|
public CacheManager cm1() {
|
||||||
|
return new NoOpCacheManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cm2() { return new NoOpCacheManager(); }
|
public CacheManager cm2() {
|
||||||
|
return new NoOpCacheManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class MultiCacheManagerConfigurer extends CachingConfigurerSupport {
|
static class MultiCacheManagerConfigurer extends CachingConfigurerSupport {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cm1() { return new NoOpCacheManager(); }
|
public CacheManager cm1() {
|
||||||
|
return new NoOpCacheManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cm2() { return new NoOpCacheManager(); }
|
public CacheManager cm2() {
|
||||||
|
return new NoOpCacheManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheManager cacheManager() {
|
public CacheManager cacheManager() {
|
||||||
return cm1();
|
return cm1();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyGenerator keyGenerator() {
|
public KeyGenerator keyGenerator() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class EmptyConfigSupportConfig extends CachingConfigurerSupport {
|
static class EmptyConfigSupportConfig extends CachingConfigurerSupport {
|
||||||
|
@ -241,6 +260,7 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class FullCachingConfig extends CachingConfigurerSupport {
|
static class FullCachingConfig extends CachingConfigurerSupport {
|
||||||
|
@ -263,4 +283,5 @@ public class EnableCachingTests extends AbstractAnnotationTests {
|
||||||
return new NamedCacheResolver(cacheManager(), "foo");
|
return new NamedCacheResolver(cacheManager(), "foo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue