Use CacheResolver in Spring abstraction
Prior to this commit, the CacheResolver was not used by Spring's caching abstraction. This commit provides the necessary configuration options to tune how a cache is resolved for a given operation. CacheResolver can be customized globally, at the operation level or at the class level. This breaks the CachingConfigurer class and a support implementation is provided that implements all methods so that the default is taken if it's not overridden. The JSR-107 support has been updated as well, with a similar support class. In particular, the static and runtime information of a cache operation were mixed which prevents any forms of caching. As the CacheResolver and the KeyGenerator can be customized, every operation call lead to a lookup in the context for the bean. This commit adds CacheOperationMetadata, a static holder of all the non-runtime metadata about a cache operation. This is used as an input source for the existing CacheOperationContext. Caching the operation metadata in an AspectJ aspect can have side effects as the aspect is static instance for the current ClassLoader. The metadata cache needs to be cleared when the context shutdowns. This is essentially a test issue only as in practice each application runs in its class loader. Tests are now closing the context properly to honor the DisposableBean callback. Issue: SPR-11490
This commit is contained in:
@@ -22,6 +22,7 @@ import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
@@ -46,6 +47,8 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
|
||||
protected CacheManager cacheManager;
|
||||
|
||||
protected CacheResolver cacheResolver;
|
||||
|
||||
protected KeyGenerator keyGenerator;
|
||||
|
||||
@Autowired(required=false)
|
||||
@@ -86,7 +89,7 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
C cachingConfigurer = cachingConfigurers.iterator().next();
|
||||
useCachingConfigurer(cachingConfigurer);
|
||||
}
|
||||
else if (!CollectionUtils.isEmpty(cacheManagerBeans)) {
|
||||
if (this.cacheManager == null && !CollectionUtils.isEmpty(cacheManagerBeans)) {
|
||||
int nManagers = cacheManagerBeans.size();
|
||||
if (nManagers > 1) {
|
||||
throw new IllegalStateException(nManagers + " beans of type CacheManager " +
|
||||
@@ -98,7 +101,7 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
this.cacheManager = cacheManagerBeans.iterator().next();
|
||||
// keyGenerator remains null; will fall back to default within CacheInterceptor
|
||||
}
|
||||
else {
|
||||
if (this.cacheManager == null) {
|
||||
throw new IllegalStateException("No bean of type CacheManager could be found. " +
|
||||
"Register a CacheManager bean or remove the @EnableCaching annotation " +
|
||||
"from your configuration.");
|
||||
@@ -110,6 +113,7 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
*/
|
||||
protected void useCachingConfigurer(C config) {
|
||||
this.cacheManager = config.cacheManager();
|
||||
this.cacheResolver = config.cacheResolver();
|
||||
this.keyGenerator = config.keyGenerator();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,21 @@ public @interface CacheConfig {
|
||||
String keyGenerator() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use.
|
||||
* <p>If none is set at the operation level, this one is used instead of the default.
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>If no resolver and no cache manager are set at the operation level, and no cache
|
||||
* resolver is set on this instance, this one is used instead of the default.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
* <p>If no resolver and no cache manager are set at the operation level, this one is used
|
||||
* instead of the default.
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -59,10 +59,19 @@ public @interface CacheEvict {
|
||||
String keyGenerator() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
|
||||
@@ -64,10 +64,19 @@ public @interface CachePut {
|
||||
String keyGenerator() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the cache update.
|
||||
* <p>Default is "", meaning the method result is always cached.
|
||||
|
||||
@@ -62,10 +62,19 @@ public @interface Cacheable {
|
||||
String keyGenerator() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -17,31 +17,39 @@
|
||||
package org.springframework.cache.annotation;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by @{@link org.springframework.context.annotation.Configuration
|
||||
* Configuration} classes annotated with @{@link EnableCaching} that wish or need to
|
||||
* specify explicitly the {@link CacheManager} and {@link KeyGenerator} beans to be used
|
||||
* for annotation-driven cache management.
|
||||
* specify explicitly how caches are resolved and how keys are generated for annotation-driven
|
||||
* cache management. Consider extending {@link CachingConfigurerSupport}, which provides a
|
||||
* stub implementation of all interface methods.
|
||||
*
|
||||
* <p>See @{@link EnableCaching} for general examples and context; see
|
||||
* {@link #cacheManager()} and {@link #keyGenerator()} for detailed instructions.
|
||||
* {@link #cacheManager()}, {@link #cacheResolver()} and {@link #keyGenerator()}
|
||||
* for detailed instructions.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see EnableCaching
|
||||
* @see CachingConfigurerSupport
|
||||
*/
|
||||
public interface CachingConfigurer {
|
||||
|
||||
/**
|
||||
* Return the cache manager bean to use for annotation-driven cache management.
|
||||
* Implementations must explicitly declare
|
||||
* Return the cache manager bean to use for annotation-driven cache
|
||||
* management. A default {@link CacheResolver} will be initialized
|
||||
* behind the scene with this cache manager. For more fine-grained
|
||||
* management of the cache resolution, consider setting the
|
||||
* {@link CacheResolver} directly.
|
||||
* <p>Implementations must explicitly declare
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableCaching
|
||||
* public class AppConfig implements CachingConfigurer {
|
||||
* public class AppConfig extends CachingConfigurerSupport {
|
||||
* @Bean // important!
|
||||
* @Override
|
||||
* public CacheManager cacheManager() {
|
||||
@@ -54,6 +62,28 @@ public interface CachingConfigurer {
|
||||
*/
|
||||
CacheManager cacheManager();
|
||||
|
||||
/**
|
||||
* Return the {@link CacheResolver} bean to use to resolve regular caches for
|
||||
* annotation-driven cache management. This is an alternative option to set
|
||||
* the {@link CacheManager} to use.
|
||||
* <p>Implementations must explicitly declare
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableCaching
|
||||
* public class AppConfig extends CachingConfigurerSupport {
|
||||
* @Bean // important!
|
||||
* @Override
|
||||
* public CacheResolver cacheResolver() {
|
||||
* // configure and return CacheResolver instance
|
||||
* }
|
||||
* // ...
|
||||
* }
|
||||
* </pre>
|
||||
* See {@link EnableCaching} for more complete examples.
|
||||
*/
|
||||
CacheResolver cacheResolver();
|
||||
|
||||
/**
|
||||
* Return the key generator bean to use for annotation-driven cache management.
|
||||
* Implementations must explicitly declare
|
||||
@@ -61,7 +91,7 @@ public interface CachingConfigurer {
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableCaching
|
||||
* public class AppConfig implements CachingConfigurer {
|
||||
* public class AppConfig extends CachingConfigurerSupport {
|
||||
* @Bean // important!
|
||||
* @Override
|
||||
* public KeyGenerator keyGenerator() {
|
||||
|
||||
48
spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java
vendored
Normal file
48
spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.annotation;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
/**
|
||||
* An implementation of {@link CachingConfigurer} with empty methods allowing
|
||||
* sub-classes to override only the methods they're interested in.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
* @see CachingConfigurer
|
||||
*/
|
||||
public class CachingConfigurerSupport implements CachingConfigurer {
|
||||
|
||||
@Override
|
||||
public CacheManager cacheManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheResolver cacheResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,7 +59,10 @@ public class ProxyCachingConfiguration extends AbstractCachingConfiguration<Cach
|
||||
public CacheInterceptor cacheInterceptor() {
|
||||
CacheInterceptor interceptor = new CacheInterceptor();
|
||||
interceptor.setCacheOperationSources(cacheOperationSource());
|
||||
if (this.cacheManager != null) {
|
||||
if (this.cacheResolver != null) {
|
||||
interceptor.setCacheResolver(this.cacheResolver);
|
||||
}
|
||||
else if (this.cacheManager != null) {
|
||||
interceptor.setCacheManager(this.cacheManager);
|
||||
}
|
||||
if (this.keyGenerator != null) {
|
||||
|
||||
@@ -105,6 +105,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
cuo.setKey(caching.key());
|
||||
cuo.setKeyGenerator(caching.keyGenerator());
|
||||
cuo.setCacheManager(caching.cacheManager());
|
||||
cuo.setCacheResolver(caching.cacheResolver());
|
||||
cuo.setName(ae.toString());
|
||||
|
||||
defaultConfig.applyDefault(cuo);
|
||||
@@ -121,6 +122,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
ceo.setKey(caching.key());
|
||||
ceo.setKeyGenerator(caching.keyGenerator());
|
||||
ceo.setCacheManager(caching.cacheManager());
|
||||
ceo.setCacheResolver(caching.cacheResolver());
|
||||
ceo.setCacheWide(caching.allEntries());
|
||||
ceo.setBeforeInvocation(caching.beforeInvocation());
|
||||
ceo.setName(ae.toString());
|
||||
@@ -140,6 +142,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
cuo.setKey(caching.key());
|
||||
cuo.setKeyGenerator(caching.keyGenerator());
|
||||
cuo.setCacheManager(caching.cacheManager());
|
||||
cuo.setCacheResolver(caching.cacheResolver());
|
||||
cuo.setName(ae.toString());
|
||||
|
||||
defaultConfig.applyDefault(cuo);
|
||||
@@ -186,8 +189,8 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
DefaultCacheConfig getDefaultCacheConfig(Class<?> target) {
|
||||
final CacheConfig annotation = AnnotationUtils.getAnnotation(target, CacheConfig.class);
|
||||
if (annotation != null) {
|
||||
return new DefaultCacheConfig(annotation.cacheManager(),
|
||||
annotation.keyGenerator(), annotation.cacheNames());
|
||||
return new DefaultCacheConfig(annotation.cacheNames(), annotation.keyGenerator(),
|
||||
annotation.cacheManager(), annotation.cacheResolver());
|
||||
}
|
||||
return new DefaultCacheConfig();
|
||||
}
|
||||
@@ -228,9 +231,16 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
"These attributes are mutually exclusive: either set the SpEL expression used to" +
|
||||
"compute the key at runtime or set the name of the KeyGenerator bean to use.");
|
||||
}
|
||||
if (StringUtils.hasText(operation.getCacheManager()) && StringUtils.hasText(operation.getCacheResolver())) {
|
||||
throw new IllegalStateException("Invalid cache annotation configuration on '"
|
||||
+ ae.toString() + "'. Both 'cacheManager' and 'cacheResolver' attributes have been set. " +
|
||||
"These attributes are mutually exclusive: the cache manager is used to configure a" +
|
||||
"default cache resolver if none is set. If a cache resolver is set, the cache manager" +
|
||||
"won't be used.");
|
||||
}
|
||||
if (operation.getCacheNames().isEmpty()) {
|
||||
throw new IllegalStateException("No cache names could be detected on '"
|
||||
+ ae.toString()+ "'. Make sure to set the value parameter on the annotation or" +
|
||||
+ ae.toString() + "'. Make sure to set the value parameter on the annotation or " +
|
||||
"declare a @CacheConfig at the class-level with the default cache name(s) to use.");
|
||||
}
|
||||
}
|
||||
@@ -245,22 +255,29 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
return SpringCacheAnnotationParser.class.hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides default settings for a given set of cache operations.
|
||||
*/
|
||||
static class DefaultCacheConfig {
|
||||
private final String cacheManager;
|
||||
private final String keyGenerator;
|
||||
private final String[] cacheNames;
|
||||
|
||||
private DefaultCacheConfig(String cacheManager, String keyGenerator, String[] cacheNames) {
|
||||
this.cacheManager = cacheManager;
|
||||
this.keyGenerator = keyGenerator;
|
||||
private final String keyGenerator;
|
||||
|
||||
private final String cacheManager;
|
||||
|
||||
private final String cacheResolver;
|
||||
|
||||
private DefaultCacheConfig(String[] cacheNames, String keyGenerator,
|
||||
String cacheManager, String cacheResolver) {
|
||||
this.cacheNames = cacheNames;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.cacheManager = cacheManager;
|
||||
this.cacheResolver = cacheResolver;
|
||||
}
|
||||
|
||||
public DefaultCacheConfig() {
|
||||
this(null, null, null);
|
||||
this(null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,17 +286,29 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
* @param operation the operation to update
|
||||
*/
|
||||
public void applyDefault(CacheOperation operation) {
|
||||
if (!StringUtils.hasText(operation.getCacheManager()) && StringUtils.hasText(cacheManager)) {
|
||||
operation.setCacheManager(cacheManager);
|
||||
if (operation.getCacheNames().isEmpty() && cacheNames != null) {
|
||||
operation.setCacheNames(cacheNames);
|
||||
}
|
||||
if (!StringUtils.hasText(operation.getKey()) && !StringUtils.hasText(operation.getKeyGenerator())
|
||||
&& StringUtils.hasText(keyGenerator)) {
|
||||
operation.setKeyGenerator(keyGenerator);
|
||||
}
|
||||
if (operation.getCacheNames().isEmpty() && cacheNames != null) {
|
||||
operation.setCacheNames(cacheNames);
|
||||
|
||||
if (isSet(operation.getCacheManager()) || isSet(operation.getCacheResolver())) {
|
||||
// One of these is set so we should not inherit anything
|
||||
}
|
||||
else if (isSet(cacheResolver)) {
|
||||
operation.setCacheResolver(cacheResolver);
|
||||
}
|
||||
else if (isSet(cacheManager)) {
|
||||
operation.setCacheManager(cacheManager);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSet(String s) {
|
||||
return StringUtils.hasText(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
92
spring-context/src/main/java/org/springframework/cache/interceptor/BaseCacheResolver.java
vendored
Normal file
92
spring-context/src/main/java/org/springframework/cache/interceptor/BaseCacheResolver.java
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A base {@link CacheResolver} implementation that requires the concrete
|
||||
* implementation to provide the collection of cache name(s) based on the
|
||||
* invocation context.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public abstract class BaseCacheResolver implements CacheResolver, InitializingBean {
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
protected BaseCacheResolver(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
protected BaseCacheResolver() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link CacheManager} that this instance should use.
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CacheManager} that this instance use.
|
||||
*/
|
||||
public CacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(cacheManager, "CacheManager must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
|
||||
Collection<String> cacheNames = getCacheNames(context);
|
||||
if (cacheNames == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
Collection<Cache> result = new ArrayList<Cache>();
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = cacheManager.getCache(cacheName);
|
||||
Assert.notNull(cache, "Cannot find cache named '" + cacheName + "' for " + context.getOperation());
|
||||
result.add(cache);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the name of the cache(s) to resolve against the current cache manager.
|
||||
* <p>It is acceptable to return {@code null} to indicate that no cache could
|
||||
* be resolved for this invocation.
|
||||
*
|
||||
* @param context the context of the particular invocation
|
||||
* @return the cache name(s) to resolve or {@code null} if no cache should be resolved
|
||||
*/
|
||||
protected abstract Collection<String> getCacheNames(CacheOperationInvocationContext<?> context);
|
||||
|
||||
}
|
||||
@@ -17,16 +17,15 @@
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
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.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
@@ -54,12 +53,12 @@ import org.springframework.util.StringUtils;
|
||||
* <p>Subclasses are responsible for calling methods in this class in
|
||||
* the correct order.
|
||||
*
|
||||
* <p>Uses the <b>Strategy</b> design pattern. A {@link CacheManager}
|
||||
* implementation will perform the actual cache management, and a
|
||||
* <p>Uses the <b>Strategy</b> design pattern. A {@link CacheResolver}
|
||||
* implementation will resolve the actual cache(s) to use, and a
|
||||
* {@link CacheOperationSource} is used for determining caching
|
||||
* operations.
|
||||
*
|
||||
* <p>A cache aspect is serializable if its {@code CacheManager} and
|
||||
* <p>A cache aspect is serializable if its {@code CacheResolver} and
|
||||
* {@code CacheOperationSource} are serializable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
@@ -74,34 +73,25 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
/**
|
||||
* Cache of CacheOperationMetadata, keyed by {@link CacheOperationCacheKey}.
|
||||
*/
|
||||
private final Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache =
|
||||
new ConcurrentHashMap<CacheOperationCacheKey, CacheOperationMetadata>(1024);
|
||||
|
||||
private CacheManager cacheManager;
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private KeyGenerator keyGenerator = new SimpleKeyGenerator();
|
||||
|
||||
private CacheResolver cacheResolver;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the default {@link CacheManager} that this cache aspect should delegate to
|
||||
* if no specific cache manager has been set for the operation.
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default {@link CacheManager} that this cache aspect delegates to.
|
||||
*/
|
||||
public CacheManager getCacheManager() {
|
||||
return this.cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -137,14 +127,46 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
return this.keyGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link CacheManager} to use to create a default {@link CacheResolver}. Replace
|
||||
* the current {@link CacheResolver}, if any.
|
||||
*
|
||||
* @see #setCacheResolver(CacheResolver)
|
||||
* @see SimpleCacheResolver
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheResolver = new SimpleCacheResolver(cacheManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default {@link CacheResolver} that this cache aspect should delegate
|
||||
* to if no specific cache resolver has been set for the operation.
|
||||
* <p>The default resolver resolves the caches against their names and the
|
||||
* default cache manager.
|
||||
* @see #setCacheManager(org.springframework.cache.CacheManager)
|
||||
* @see SimpleCacheResolver
|
||||
*/
|
||||
public void setCacheResolver(CacheResolver cacheResolver) {
|
||||
Assert.notNull(cacheResolver);
|
||||
this.cacheResolver = cacheResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default {@link CacheResolver} that this cache aspect delegates to.
|
||||
*/
|
||||
public CacheResolver getCacheResolver() {
|
||||
return cacheResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.state(this.cacheManager != null, "Property 'cacheManager' is required");
|
||||
Assert.state(this.cacheOperationSource != null, "Property 'cacheOperationSources' is required: " +
|
||||
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.");
|
||||
Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSources' property is required: " +
|
||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||
Assert.state(this.applicationContext != null, "The application context was not injected as it should.");
|
||||
this.initialized = true;
|
||||
@@ -165,21 +187,85 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||
}
|
||||
|
||||
protected Collection<? extends Cache> getCaches(CacheOperation operation, CacheManager cacheManager) {
|
||||
Set<String> cacheNames = operation.getCacheNames();
|
||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = cacheManager.getCache(cacheName);
|
||||
Assert.notNull(cache, "Cannot find cache named '" + cacheName + "' for " + operation);
|
||||
caches.add(cache);
|
||||
protected Collection<? extends Cache> getCaches(CacheOperationInvocationContext<CacheOperation> context,
|
||||
CacheResolver cacheResolver) {
|
||||
Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
|
||||
if (caches.isEmpty()) {
|
||||
throw new IllegalStateException("No cache could be resolved for '" + context.getOperation()
|
||||
+ "' using resolver '" + cacheResolver
|
||||
+ "'. At least one cache should be provided per cache operation.");
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
Object target, Class<?> targetClass) {
|
||||
|
||||
return new CacheOperationContext(operation, method, args, target, targetClass);
|
||||
CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
|
||||
return new CacheOperationContext(metadata, args, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CacheOperationMetadata} for the specified operation.
|
||||
* <p>Resolve the {@link CacheResolver} and the {@link KeyGenerator} to be
|
||||
* used for the operation.
|
||||
* @param operation the operation
|
||||
* @param method the method on which the operation is invoked
|
||||
* @param targetClass the target type
|
||||
* @return the resolved metadata for the operation
|
||||
*/
|
||||
protected CacheOperationMetadata getCacheOperationMetadata(CacheOperation operation,
|
||||
Method method, Class<?> targetClass) {
|
||||
final CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
|
||||
CacheOperationMetadata metadata = metadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
KeyGenerator operationKeyGenerator;
|
||||
if (StringUtils.hasText(operation.getKeyGenerator())) {
|
||||
operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
|
||||
}
|
||||
else {
|
||||
operationKeyGenerator = getKeyGenerator();
|
||||
}
|
||||
CacheResolver operationCacheResolver;
|
||||
if (StringUtils.hasText(operation.getCacheResolver())) {
|
||||
operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
|
||||
}
|
||||
else if (StringUtils.hasText(operation.getCacheManager())) {
|
||||
CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
|
||||
operationCacheResolver = new SimpleCacheResolver(cacheManager);
|
||||
}
|
||||
else {
|
||||
operationCacheResolver = getCacheResolver();
|
||||
}
|
||||
metadata = new CacheOperationMetadata(operation, method, targetClass,
|
||||
operationKeyGenerator, operationCacheResolver);
|
||||
metadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean with the specified name and type. Used to resolve services that
|
||||
* are referenced by name in a {@link CacheOperation}.
|
||||
*
|
||||
* @param beanName the name of the bean, as defined by the operation
|
||||
* @param expectedType type type for the bean
|
||||
* @return the bean matching that name
|
||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if such bean does not exist
|
||||
* @see CacheOperation#keyGenerator
|
||||
* @see CacheOperation#cacheManager
|
||||
* @see CacheOperation#cacheResolver
|
||||
*/
|
||||
protected <T> T getBean(String beanName, Class<T> expectedType) {
|
||||
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
||||
applicationContext, expectedType, beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cached metadata.
|
||||
*/
|
||||
protected void clearMetadataCache() {
|
||||
metadataCache.clear();
|
||||
}
|
||||
|
||||
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
|
||||
@@ -245,7 +331,7 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
|
||||
private void processCacheEvicts(Collection<CacheOperationContext> contexts, boolean beforeInvocation, Object result) {
|
||||
for (CacheOperationContext context : contexts) {
|
||||
CacheEvictOperation operation = (CacheEvictOperation) context.operation;
|
||||
CacheEvictOperation operation = (CacheEvictOperation) context.metadata.operation;
|
||||
if (beforeInvocation == operation.isBeforeInvocation() && isConditionPassing(context, result)) {
|
||||
performCacheEvict(context, operation, result);
|
||||
}
|
||||
@@ -272,7 +358,7 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
private void logInvalidating(CacheOperationContext context, CacheEvictOperation operation, Object key) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Invalidating " + (key != null ? "cache key [" + key + "]" : "entire cache") +
|
||||
" for operation " + operation + " on method " + context.method);
|
||||
" for operation " + operation + " on method " + context.metadata.method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +413,8 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
private boolean isConditionPassing(CacheOperationContext context, Object result) {
|
||||
boolean passing = context.isConditionPassing(result);
|
||||
if (!passing && logger.isTraceEnabled()) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
|
||||
logger.trace("Cache condition failed on method " + context.metadata.method +
|
||||
" for operation " + context.metadata.operation);
|
||||
}
|
||||
return passing;
|
||||
}
|
||||
@@ -335,9 +422,9 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
private Object generateKey(CacheOperationContext context, Object result) {
|
||||
Object key = context.generateKey(result);
|
||||
Assert.notNull(key, "Null key returned for cache operation (maybe you are using named params " +
|
||||
"on classes without debug info?) " + context.operation);
|
||||
"on classes without debug info?) " + context.metadata.operation);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Computed cache key " + key + " for operation " + context.operation);
|
||||
logger.trace("Computed cache key " + key + " for operation " + context.metadata.operation);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
@@ -349,7 +436,7 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
new LinkedMultiValueMap<Class<? extends CacheOperation>, CacheOperationContext>();
|
||||
|
||||
public CacheOperationContexts(Collection<? extends CacheOperation> operations,
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
for (CacheOperation operation : operations) {
|
||||
this.contexts.add(operation.getClass(), getOperationContext(operation, method, args, target, targetClass));
|
||||
@@ -358,51 +445,70 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
|
||||
public Collection<CacheOperationContext> get(Class<? extends CacheOperation> operationClass) {
|
||||
Collection<CacheOperationContext> result = this.contexts.get(operationClass);
|
||||
return (result != null ? result : Collections.<CacheOperationContext> emptyList());
|
||||
return (result != null ? result : Collections.<CacheOperationContext>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected class CacheOperationContext {
|
||||
/**
|
||||
* Metadata of a cache operation that does not depend on a particular invocation
|
||||
* which makes it a good candidate for caching.
|
||||
*/
|
||||
protected static class CacheOperationMetadata {
|
||||
|
||||
private final CacheOperation operation;
|
||||
|
||||
private final Method method;
|
||||
private final Class<?> targetClass;
|
||||
private final KeyGenerator keyGenerator;
|
||||
private final CacheResolver cacheResolver;
|
||||
|
||||
public CacheOperationMetadata(CacheOperation operation, Method method,
|
||||
Class<?> targetClass, KeyGenerator keyGenerator,
|
||||
CacheResolver cacheResolver) {
|
||||
this.operation = operation;
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.cacheResolver = cacheResolver;
|
||||
}
|
||||
}
|
||||
|
||||
protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
|
||||
|
||||
private final CacheOperationMetadata metadata;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Collection<? extends Cache> caches;
|
||||
|
||||
private final KeyGenerator operationKeyGenerator;
|
||||
|
||||
private final CacheManager operationCacheManager;
|
||||
|
||||
public CacheOperationContext(CacheOperation operation, Method method,
|
||||
Object[] args, Object target, Class<?> targetClass) {
|
||||
this.operation = operation;
|
||||
this.method = method;
|
||||
this.args = extractArgs(method, args);
|
||||
public CacheOperationContext(CacheOperationMetadata metadata,
|
||||
Object[] args, Object target) {
|
||||
this.metadata = metadata;
|
||||
this.args = extractArgs(metadata.method, args);
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
if (StringUtils.hasText(operation.getKeyGenerator())) { // TODO: exception mgt?
|
||||
this.operationKeyGenerator = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
||||
applicationContext, KeyGenerator.class, operation.getKeyGenerator());
|
||||
}
|
||||
else {
|
||||
this.operationKeyGenerator = keyGenerator;
|
||||
}
|
||||
if (StringUtils.hasText(operation.getCacheManager())) {
|
||||
this.operationCacheManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
||||
applicationContext, CacheManager.class, operation.getCacheManager());
|
||||
}
|
||||
else {
|
||||
this.operationCacheManager = cacheManager;
|
||||
}
|
||||
this.caches = CacheAspectSupport.this.getCaches(operation, operationCacheManager);
|
||||
this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheOperation getOperation() {
|
||||
return metadata.operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getMethod() {
|
||||
return metadata.method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
private Object[] extractArgs(Method method, Object[] args) {
|
||||
@@ -417,24 +523,24 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
}
|
||||
|
||||
protected boolean isConditionPassing(Object result) {
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
|
||||
return evaluator.condition(this.metadata.operation.getCondition(), this.metadata.method, evaluationContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean canPutToCache(Object value) {
|
||||
String unless = "";
|
||||
if (this.operation instanceof CacheableOperation) {
|
||||
unless = ((CacheableOperation) this.operation).getUnless();
|
||||
if (this.metadata.operation instanceof CacheableOperation) {
|
||||
unless = ((CacheableOperation) this.metadata.operation).getUnless();
|
||||
}
|
||||
else if (this.operation instanceof CachePutOperation) {
|
||||
unless = ((CachePutOperation) this.operation).getUnless();
|
||||
else if (this.metadata.operation instanceof CachePutOperation) {
|
||||
unless = ((CachePutOperation) this.metadata.operation).getUnless();
|
||||
}
|
||||
if (StringUtils.hasText(unless)) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(value);
|
||||
return !evaluator.unless(unless, this.method, evaluationContext);
|
||||
return !evaluator.unless(unless, this.metadata.method, evaluationContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -444,16 +550,16 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
* @return generated key (null if none can be generated)
|
||||
*/
|
||||
protected Object generateKey(Object result) {
|
||||
if (StringUtils.hasText(this.operation.getKey())) {
|
||||
if (StringUtils.hasText(this.metadata.operation.getKey())) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||
return evaluator.key(this.operation.getKey(), this.method, evaluationContext);
|
||||
return evaluator.key(this.metadata.operation.getKey(), this.metadata.method, evaluationContext);
|
||||
}
|
||||
return operationKeyGenerator.generate(this.target, this.method, this.args);
|
||||
return metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
|
||||
}
|
||||
|
||||
private EvaluationContext createEvaluationContext(Object result) {
|
||||
return evaluator.createEvaluationContext(
|
||||
this.caches, this.method, this.args, this.target, this.targetClass, result);
|
||||
this.caches, this.metadata.method, this.args, this.target, this.metadata.targetClass, result);
|
||||
}
|
||||
|
||||
protected Collection<? extends Cache> getCaches() {
|
||||
@@ -482,4 +588,31 @@ public abstract class CacheAspectSupport implements InitializingBean, Applicatio
|
||||
}
|
||||
}
|
||||
|
||||
private static class CacheOperationCacheKey {
|
||||
|
||||
private final CacheOperation cacheOperation;
|
||||
private final MethodCacheKey methodCacheKey;
|
||||
|
||||
private CacheOperationCacheKey(CacheOperation cacheOperation, Method method, Class<?> targetClass) {
|
||||
this.cacheOperation = cacheOperation;
|
||||
this.methodCacheKey = new MethodCacheKey(method, targetClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CacheOperationCacheKey that = (CacheOperationCacheKey) o;
|
||||
return cacheOperation.equals(that.cacheOperation)
|
||||
&& methodCacheKey.equals(that.methodCacheKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = cacheOperation.hashCode();
|
||||
result = 31 * result + methodCacheKey.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.util.Assert;
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public abstract class CacheOperation {
|
||||
public abstract class CacheOperation implements BasicCacheOperation {
|
||||
|
||||
private Set<String> cacheNames = Collections.emptySet();
|
||||
|
||||
@@ -40,9 +40,12 @@ public abstract class CacheOperation {
|
||||
|
||||
private String cacheManager = "";
|
||||
|
||||
private String cacheResolver = "";
|
||||
|
||||
private String name = "";
|
||||
|
||||
|
||||
@Override
|
||||
public Set<String> getCacheNames() {
|
||||
return cacheNames;
|
||||
}
|
||||
@@ -63,6 +66,10 @@ public abstract class CacheOperation {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public String getCacheResolver() {
|
||||
return cacheResolver;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -100,6 +107,11 @@ public abstract class CacheOperation {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
public void setCacheResolver(String cacheResolver) {
|
||||
Assert.notNull(cacheManager);
|
||||
this.cacheResolver = cacheResolver;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
Assert.hasText(name);
|
||||
this.name = name;
|
||||
@@ -151,6 +163,8 @@ public abstract class CacheOperation {
|
||||
result.append(this.keyGenerator);
|
||||
result.append("' | cacheManager='");
|
||||
result.append(this.cacheManager);
|
||||
result.append("' | cacheResolver='");
|
||||
result.append(this.cacheResolver);
|
||||
result.append("' | condition='");
|
||||
result.append(this.condition);
|
||||
result.append("'");
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -21,7 +37,6 @@ public final class MethodCacheKey {
|
||||
|
||||
public MethodCacheKey(Method method, Class<?> targetClass) {
|
||||
Assert.notNull(method, "method must be set.");
|
||||
Assert.notNull(targetClass, "targetClass must be set.");
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
56
spring-context/src/main/java/org/springframework/cache/interceptor/NamedCacheResolver.java
vendored
Normal file
56
spring-context/src/main/java/org/springframework/cache/interceptor/NamedCacheResolver.java
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* A {@link CacheResolver} that forces the resolution to a configurable
|
||||
* collection of name(s) against a given {@link CacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class NamedCacheResolver extends BaseCacheResolver {
|
||||
|
||||
private Collection<String> cacheNames;
|
||||
|
||||
public NamedCacheResolver(CacheManager cacheManager, String... cacheNames) {
|
||||
super(cacheManager);
|
||||
this.cacheNames = new ArrayList<String>(Arrays.asList(cacheNames));
|
||||
}
|
||||
|
||||
public NamedCacheResolver() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache name(s) that this resolver should use.
|
||||
*/
|
||||
public void setCacheNames(Collection<String> cacheNames) {
|
||||
this.cacheNames = cacheNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,39 +16,29 @@
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A simple {@link CacheResolver} that resolves the {@link Cache} instance(s)
|
||||
* based on a configurable {@link CacheManager} and the name of the
|
||||
* cache(s): {@link BasicCacheOperation#getCacheNames()}
|
||||
* cache(s) as provided by {@link BasicCacheOperation#getCacheNames() getCacheNames()}
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
* @see BasicCacheOperation#getCacheNames()
|
||||
*/
|
||||
public class SimpleCacheResolver implements CacheResolver {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
public class SimpleCacheResolver extends BaseCacheResolver {
|
||||
|
||||
public SimpleCacheResolver(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
super(cacheManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
|
||||
Collection<Cache> result = new ArrayList<Cache>();
|
||||
for (String cacheName : context.getOperation().getCacheNames()) {
|
||||
Cache cache = cacheManager.getCache(cacheName);
|
||||
Assert.notNull(cache, "Cannot find cache named '" + cacheName + "' for " + context.getOperation());
|
||||
result.add(cache);
|
||||
}
|
||||
return result;
|
||||
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
|
||||
return context.getOperation().getCacheNames();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user