general revision of cache package; added ConcurrentMapCacheManager
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,73 +16,67 @@
|
||||
|
||||
package org.springframework.cache;
|
||||
|
||||
|
||||
/**
|
||||
* Interface that defines the common cache operations.
|
||||
*
|
||||
*
|
||||
* <b>Note:</b> Due to the generic use of caching, it is recommended that
|
||||
* implementations allow storage of <tt>null</tt> values (for example to
|
||||
* cache methods that return null).
|
||||
*
|
||||
* cache methods that return <code>null</code>).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface Cache {
|
||||
|
||||
/**
|
||||
* Return the cache name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the the underlying native cache provider.
|
||||
*/
|
||||
Object getNativeCache();
|
||||
|
||||
/**
|
||||
* Return the value to which this cache maps the specified key. Returns
|
||||
* <code>null</code> if the cache contains no mapping for this key.
|
||||
* @param key key whose associated value is to be returned.
|
||||
* @return the value to which this cache maps the specified key,
|
||||
* or <code>null</code> if the cache contains no mapping for this key
|
||||
*/
|
||||
ValueWrapper get(Object key);
|
||||
|
||||
/**
|
||||
* Associate the specified value with the specified key in this cache.
|
||||
* <p>If the cache previously contained a mapping for this key, the old
|
||||
* value is replaced by the specified value.
|
||||
* @param key the key with which the specified value is to be associated
|
||||
* @param value the value to be associated with the specified key
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* Evict the mapping for this key from this cache if it is present.
|
||||
* @param key the key whose mapping is to be removed from the cache
|
||||
*/
|
||||
void evict(Object key);
|
||||
|
||||
/**
|
||||
* Remove all mappings from the cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
/**
|
||||
* A (wrapper) object representing a cache value.
|
||||
*/
|
||||
interface ValueWrapper {
|
||||
|
||||
/**
|
||||
* Returns the actual value in the cache.
|
||||
*
|
||||
* @return cache value
|
||||
* Return the actual value in the cache.
|
||||
*/
|
||||
Object get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache name.
|
||||
*
|
||||
* @return the cache name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the the native, underlying cache provider.
|
||||
*
|
||||
* @return the underlying native cache provider.
|
||||
*/
|
||||
Object getNativeCache();
|
||||
|
||||
/**
|
||||
* Returns the value to which this cache maps the specified key. Returns
|
||||
* <tt>null</tt> if the cache contains no mapping for this key.
|
||||
*
|
||||
* @param key key whose associated value is to be returned.
|
||||
* @return the value to which this cache maps the specified key, or
|
||||
* <tt>null</tt> if the cache contains no mapping for this key.
|
||||
*/
|
||||
ValueWrapper get(Object key);
|
||||
|
||||
/**
|
||||
* Associates the specified value with the specified key in this cache.
|
||||
* If the cache previously contained a mapping for this key, the old
|
||||
* value is replaced by the specified value.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated.
|
||||
* @param value value to be associated with the specified key.
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* Evicts the mapping for this key from this cache if it is present.
|
||||
*
|
||||
* @param key key whose mapping is to be removed from the cache.
|
||||
*/
|
||||
void evict(Object key);
|
||||
|
||||
/**
|
||||
* Removes all mappings from the cache.
|
||||
*/
|
||||
void clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,26 +18,25 @@ package org.springframework.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Entity managing {@link Cache}s.
|
||||
*
|
||||
* A manager for a set of {@link Cache}s.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheManager {
|
||||
|
||||
/**
|
||||
* Returns the cache associated with the given name.
|
||||
*
|
||||
* @param name cache identifier - cannot be null
|
||||
* @return associated cache or null if none is found
|
||||
* Return the cache associated with the given name.
|
||||
* @param name cache identifier (must not be <code>null</code>)
|
||||
* @return associated cache, or <code>null</code> if none is found
|
||||
*/
|
||||
Cache getCache(String name);
|
||||
|
||||
/**
|
||||
* Returns a collection of the caches known by this cache manager.
|
||||
*
|
||||
* @return names of caches known by the cache manager.
|
||||
* Return a collection of the caches known by this cache manager.
|
||||
* @return names of caches known by the cache manager.
|
||||
*/
|
||||
Collection<String> getCacheNames();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,29 +37,28 @@ import org.springframework.util.Assert;
|
||||
* This class may also serve as base class for a custom CacheOperationSource.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements
|
||||
Serializable {
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource
|
||||
implements Serializable {
|
||||
|
||||
private final boolean publicMethodsOnly;
|
||||
|
||||
private final Set<CacheAnnotationParser> annotationParsers;
|
||||
|
||||
|
||||
/**
|
||||
* Create a default AnnotationCacheOperationSource, supporting
|
||||
* public methods that carry the <code>Cacheable</code> and <code>CacheEvict</code>
|
||||
* annotations.
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
*/
|
||||
public AnnotationCacheOperationSource() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom AnnotationCacheOperationSource, supporting
|
||||
* public methods that carry the <code>Cacheable</code> and
|
||||
* <code>CacheEvict</code> annotations.
|
||||
*
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
* @param publicMethodsOnly whether to support only annotated public methods
|
||||
* typically for use with proxy-based AOP), or protected/private methods as well
|
||||
* (typically used with AspectJ class weaving)
|
||||
@@ -67,7 +66,7 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
||||
public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
|
||||
this.publicMethodsOnly = publicMethodsOnly;
|
||||
this.annotationParsers = new LinkedHashSet<CacheAnnotationParser>(1);
|
||||
this.annotationParsers.add(new SpringCachingAnnotationParser());
|
||||
this.annotationParsers.add(new SpringCacheAnnotationParser());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +81,7 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
||||
this.annotationParsers = parsers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CacheOperation findCacheOperation(Class<?> clazz) {
|
||||
return determineCacheOperation(clazz);
|
||||
@@ -120,4 +120,5 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return this.publicMethodsOnly;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.cache.interceptor.CacheOperation;
|
||||
* {@link Cacheable} or {@link CacheEvict}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheAnnotationParser {
|
||||
|
||||
@@ -43,4 +44,5 @@ public interface CacheAnnotationParser {
|
||||
* @see AnnotationCacheOperationSource#determineCacheOperation
|
||||
*/
|
||||
CacheOperation parseCacheAnnotation(AnnotatedElement ae);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,11 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a cache invalidate operation.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target( { ElementType.METHOD, ElementType.TYPE })
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@@ -44,24 +45,22 @@ public @interface CacheEvict {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p/>
|
||||
* Default is "" meaning all method parameters are considered as a key.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p/>
|
||||
* Default is "" meaning the method is always cached.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Whether or not all the entries inside the cache(s) are removed or not. By
|
||||
* default, only the value under the associated key is removed.
|
||||
*
|
||||
* Note that specifying setting this parameter to true and specifying a
|
||||
* <p>Note that specifying setting this parameter to true and specifying a
|
||||
* {@link CacheKey key} is not allowed.
|
||||
*/
|
||||
boolean allEntries() default false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,10 +25,12 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all the methods on a class) can be cached.
|
||||
* The method arguments and signature are used for computing the key while the return instance
|
||||
* as the cache value.
|
||||
*
|
||||
*
|
||||
* <p>The method arguments and signature are used for computing the key while the
|
||||
* returned instance is used as the cache value.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -55,4 +57,4 @@ public @interface Cacheable {
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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 java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CacheUpdateOperation;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing Spring's {@link Cacheable} and {@link CacheEvict} annotations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
|
||||
|
||||
public CacheOperation parseCacheAnnotation(AnnotatedElement ae) {
|
||||
Cacheable update = AnnotationUtils.getAnnotation(ae, Cacheable.class);
|
||||
if (update != null) {
|
||||
return parseCacheableAnnotation(ae, update);
|
||||
}
|
||||
CacheEvict evict = AnnotationUtils.getAnnotation(ae, CacheEvict.class);
|
||||
if (evict != null) {
|
||||
return parseEvictAnnotation(ae, evict);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
CacheUpdateOperation parseCacheableAnnotation(AnnotatedElement ae, Cacheable ann) {
|
||||
CacheUpdateOperation cuo = new CacheUpdateOperation();
|
||||
cuo.setCacheNames(ann.value());
|
||||
cuo.setCondition(ann.condition());
|
||||
cuo.setKey(ann.key());
|
||||
cuo.setName(ae.toString());
|
||||
return cuo;
|
||||
}
|
||||
|
||||
CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, CacheEvict ann) {
|
||||
CacheEvictOperation ceo = new CacheEvictOperation();
|
||||
ceo.setCacheNames(ann.value());
|
||||
ceo.setCondition(ann.condition());
|
||||
ceo.setKey(ann.key());
|
||||
ceo.setCacheWide(ann.allEntries());
|
||||
ceo.setName(ae.toString());
|
||||
return ceo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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 java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CacheUpdateOperation;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing Spring's {@link Cacheable} and {@link CacheEvict} annotations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringCachingAnnotationParser implements CacheAnnotationParser, Serializable {
|
||||
|
||||
public CacheOperation parseCacheAnnotation(AnnotatedElement ae) {
|
||||
Cacheable update = findAnnotation(ae, Cacheable.class);
|
||||
|
||||
if (update != null) {
|
||||
return parseCacheableAnnotation(ae, update);
|
||||
}
|
||||
|
||||
CacheEvict invalidate = findAnnotation(ae, CacheEvict.class);
|
||||
|
||||
if (invalidate != null) {
|
||||
return parseEvictAnnotation(ae, invalidate);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T extends Annotation> T findAnnotation(AnnotatedElement ae, Class<T> annotationType) {
|
||||
T ann = ae.getAnnotation(annotationType);
|
||||
if (ann == null) {
|
||||
for (Annotation metaAnn : ae.getAnnotations()) {
|
||||
ann = metaAnn.annotationType().getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ann;
|
||||
}
|
||||
|
||||
CacheUpdateOperation parseCacheableAnnotation(AnnotatedElement target, Cacheable ann) {
|
||||
CacheUpdateOperation dcud = new CacheUpdateOperation();
|
||||
dcud.setCacheNames(ann.value());
|
||||
dcud.setCondition(ann.condition());
|
||||
dcud.setKey(ann.key());
|
||||
dcud.setName(target.toString());
|
||||
|
||||
return dcud;
|
||||
}
|
||||
|
||||
CacheEvictOperation parseEvictAnnotation(AnnotatedElement target, CacheEvict ann) {
|
||||
CacheEvictOperation dcid = new CacheEvictOperation();
|
||||
dcid.setCacheNames(ann.value());
|
||||
dcid.setCondition(ann.condition());
|
||||
dcid.setKey(ann.key());
|
||||
dcid.setCacheWide(ann.allEntries());
|
||||
dcid.setName(target.toString());
|
||||
|
||||
return dcid;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,86 +17,129 @@
|
||||
package org.springframework.cache.concurrent;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.DefaultValueWrapper;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
|
||||
/**
|
||||
* Simple {@link Cache} implementation based on the JDK 1.5+
|
||||
* java.util.concurrent package. Useful for testing or simple caching scenarios.
|
||||
* Simple {@link Cache} implementation based on the core JDK
|
||||
* <code>java.util.concurrent</code> package.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
* dynamically through {@link ConcurrentMapCacheManager}.
|
||||
*
|
||||
* <p><b>Note:</b> As {@link ConcurrentHashMap} (the default implementation used)
|
||||
* does not allow for <code>null</code> values to be stored, this class will replace
|
||||
* them with a predefined internal object. This behavior can be changed through the
|
||||
* {@link #ConcurrentMapCache(String, ConcurrentMap, boolean)} constructor.
|
||||
*
|
||||
* <b>Note:</b>As {@link ConcurrentHashMap} (the default implementation used) does not allow null values to be stored
|
||||
* this class will replace them with a predefined, internal object. This behaviour can be changed through the {@link #ConcurrentMapCache(ConcurrentMap, String, boolean)}
|
||||
* constructor.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCache implements Cache {
|
||||
|
||||
private static class NullHolder implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
private static final Object NULL_HOLDER = new NullHolder();
|
||||
private final ConcurrentMap store;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final ConcurrentMap<Object, Object> store;
|
||||
|
||||
private final boolean allowNullValues;
|
||||
|
||||
public ConcurrentMapCache() {
|
||||
this("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name) {
|
||||
this(new ConcurrentHashMap(), name, true);
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), true);
|
||||
}
|
||||
|
||||
public ConcurrentMapCache(ConcurrentMap delegate, String name, boolean allowNullValues) {
|
||||
this.store = delegate;
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name, boolean allowNullValues) {
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), allowNullValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name and the
|
||||
* given internal ConcurrentMap to use.
|
||||
* @param name the name of the cache
|
||||
* @param store the ConcurrentMap to use as an internal store
|
||||
* @param allowNullValues whether to allow <code>null</code> values
|
||||
* (adapting them to an internal null holder value)
|
||||
*/
|
||||
public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {
|
||||
this.name = name;
|
||||
this.store = store;
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean getAllowNullValues() {
|
||||
return allowNullValues;
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public ConcurrentMap getNativeCache() {
|
||||
return store;
|
||||
return this.store;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
store.clear();
|
||||
public boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Object v = store.get(key);
|
||||
return (v != null ? new DefaultValueWrapper(filterNull(v)) : null);
|
||||
Object value = this.store.get(key);
|
||||
return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
if (allowNullValues && value == null) {
|
||||
Map map = store;
|
||||
map.put(key, NULL_HOLDER);
|
||||
} else {
|
||||
store.put(key, value);
|
||||
}
|
||||
this.store.put(key, toStoreValue(value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
store.remove(key);
|
||||
this.store.remove(key);
|
||||
}
|
||||
|
||||
protected Object filterNull(Object val) {
|
||||
if (allowNullValues && val == NULL_HOLDER) {
|
||||
public void clear() {
|
||||
this.store.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given value from the internal store to a user value
|
||||
* returned from the get method (adapting <code>null</code>).
|
||||
* @param userValue the store value
|
||||
* @return the value to return to the user
|
||||
*/
|
||||
protected Object fromStoreValue(Object storeValue) {
|
||||
if (this.allowNullValues && storeValue == NULL_HOLDER) {
|
||||
return null;
|
||||
}
|
||||
return val;
|
||||
return storeValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given user value, as passed into the put method,
|
||||
* to a value in the internal store (adapting <code>null</code>).
|
||||
* @param userValue the given user value
|
||||
* @return the value to store
|
||||
*/
|
||||
protected Object toStoreValue(Object userValue) {
|
||||
if (this.allowNullValues && userValue == null) {
|
||||
return NULL_HOLDER;
|
||||
}
|
||||
return userValue;
|
||||
}
|
||||
|
||||
|
||||
private static class NullHolder implements Serializable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,45 +24,78 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory bean for easy configuration of {@link ConcurrentMapCache} through Spring.
|
||||
*
|
||||
* {@link FactoryBean} for easy configuration of a {@link ConcurrentMapCache}
|
||||
* when used within a Spring container. Can be configured through bean properties;
|
||||
* uses the assigned Spring bean name as the default cache name.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
* dynamically through {@link ConcurrentMapCacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCacheFactoryBean implements FactoryBean<ConcurrentMapCache>, BeanNameAware,
|
||||
InitializingBean {
|
||||
public class ConcurrentMapCacheFactoryBean
|
||||
implements FactoryBean<ConcurrentMapCache>, BeanNameAware, InitializingBean {
|
||||
|
||||
private String name = "";
|
||||
|
||||
private ConcurrentMap<Object, Object> store;
|
||||
|
||||
private boolean allowNullValues = true;
|
||||
|
||||
private ConcurrentMapCache cache;
|
||||
|
||||
private ConcurrentMap store;
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
cache = (store == null ? new ConcurrentMapCache(name) : new ConcurrentMapCache(store, name, true));
|
||||
/**
|
||||
* Specify the name of the cache.
|
||||
* <p>Default is "" (empty String).
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ConcurrentMapCache getObject() throws Exception {
|
||||
return cache;
|
||||
/**
|
||||
* Specify the ConcurrentMap to use as an internal store
|
||||
* (possibly pre-populated).
|
||||
* <p>Default is a standard {@link java.util.concurrent.ConcurrentHashMap}.
|
||||
*/
|
||||
public void setStore(ConcurrentMap<Object, Object> store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to allow <code>null</code> values
|
||||
* (adapting them to an internal null holder value).
|
||||
* <p>Default is "true".
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
if (!StringUtils.hasLength(this.name)) {
|
||||
setName(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.cache = (this.store != null ? new ConcurrentMapCache(this.name, this.store, this.allowNullValues) :
|
||||
new ConcurrentMapCache(this.name, this.allowNullValues));
|
||||
}
|
||||
|
||||
|
||||
public ConcurrentMapCache getObject() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return (cache != null ? cache.getClass() : ConcurrentMapCache.class);
|
||||
return ConcurrentMapCache.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
setName(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setStore(ConcurrentMap store) {
|
||||
this.store = store;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.concurrent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* {@link CacheManager} implementation that lazily builds {@link ConcurrentMapCache}
|
||||
* instances for each {@link #getCache} request. Also supports a 'static' mode where
|
||||
* the set of cache names is pre-defined through {@link #setCacheNames}, with no
|
||||
* dynamic creation of further cache regions at runtime.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCacheManager implements CacheManager {
|
||||
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
private boolean dynamic = true;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a dynamic ConcurrentMapCacheManager,
|
||||
* lazily creating cache instances as they are being requested.
|
||||
*/
|
||||
public ConcurrentMapCacheManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a static ConcurrentMapCacheManager,
|
||||
* managing caches for the specified cache names only.
|
||||
*/
|
||||
public ConcurrentMapCacheManager(String... cacheNames) {
|
||||
setCacheNames(Arrays.asList(cacheNames));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the set of cache names for this CacheManager's 'static' mode.
|
||||
* <p>The number of caches and their names will be fixed after a call to this method,
|
||||
* with no creation of further cache regions at runtime.
|
||||
*/
|
||||
public void setCacheNames(Collection<String> cacheNames) {
|
||||
if (cacheNames != null) {
|
||||
for (String name : cacheNames) {
|
||||
this.cacheMap.put(name, createConcurrentMapCache(name));
|
||||
}
|
||||
this.dynamic = false;
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
return Collections.unmodifiableSet(this.cacheMap.keySet());
|
||||
}
|
||||
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = this.cacheMap.get(name);
|
||||
if (cache == null && this.dynamic) {
|
||||
synchronized (this.cacheMap) {
|
||||
cache = this.cacheMap.get(name);
|
||||
if (cache == null) {
|
||||
cache = createConcurrentMapCache(name);
|
||||
this.cacheMap.put(name, cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache instance for the specified cache name.
|
||||
* @param name the name of the cache
|
||||
* @return the ConcurrentMapCache (or a decorator thereof)
|
||||
*/
|
||||
protected Cache createConcurrentMapCache(String name) {
|
||||
return new ConcurrentMapCache(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -29,7 +29,8 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
@@ -43,6 +44,7 @@ import org.w3c.dom.Element;
|
||||
* will result in class-based proxies being created.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
@@ -111,7 +113,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) {
|
||||
Object eleSource = parserContext.extractSource(element);
|
||||
|
||||
// Create the CacheDefinitionSource definition.
|
||||
// Create the CacheOperationSource definition.
|
||||
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class);
|
||||
sourceDef.setSource(eleSource);
|
||||
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
@@ -122,14 +124,14 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
interceptorDef.setSource(eleSource);
|
||||
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registerCacheManagerProperty(element, interceptorDef);
|
||||
interceptorDef.getPropertyValues().add("cacheDefinitionSources", new RuntimeBeanReference(sourceName));
|
||||
interceptorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||
|
||||
// Create the CacheAdvisor definition.
|
||||
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
|
||||
advisorDef.setSource(eleSource);
|
||||
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisorDef.getPropertyValues().add("cacheDefinitionSource", new RuntimeBeanReference(sourceName));
|
||||
advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
||||
if (element.hasAttribute("order")) {
|
||||
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
|
||||
@@ -145,4 +147,5 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,12 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
* Spring cache management facilities.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,53 +21,57 @@ import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.DefaultValueWrapper;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCache implements Cache {
|
||||
|
||||
private final Ehcache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@link EhCacheCache} instance.
|
||||
*
|
||||
* Create an {@link EhCacheCache} instance.
|
||||
* @param ehcache backing Ehcache instance
|
||||
*/
|
||||
public EhCacheCache(Ehcache ehcache) {
|
||||
Assert.notNull(ehcache, "non null ehcache required");
|
||||
Assert.notNull(ehcache, "Ehcache must not be null");
|
||||
Status status = ehcache.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status), "an 'alive' ehcache is required - current cache is "
|
||||
+ status.toString());
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' Ehcache is required - current cache is " + status.toString());
|
||||
this.cache = ehcache;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return cache.getName();
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
public Ehcache getNativeCache() {
|
||||
return cache;
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
cache.removeAll();
|
||||
this.cache.removeAll();
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Element element = cache.get(key);
|
||||
return (element != null ? new DefaultValueWrapper(element.getObjectValue()) : null);
|
||||
Element element = this.cache.get(key);
|
||||
return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
cache.put(new Element(key, value));
|
||||
this.cache.put(new Element(key, value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
cache.remove(key);
|
||||
this.cache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,55 +27,53 @@ import org.springframework.cache.support.AbstractCacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CacheManager backed by an Ehcache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCacheManager extends AbstractCacheManager {
|
||||
|
||||
private net.sf.ehcache.CacheManager cacheManager;
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Assert.notNull(cacheManager, "a backing Ehcache cache manager is required");
|
||||
Status status = cacheManager.getStatus();
|
||||
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"an 'alive' Ehcache cache manager is required - current cache is " + status.toString());
|
||||
|
||||
String[] names = cacheManager.getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(cacheManager.getEhcache(name)));
|
||||
}
|
||||
|
||||
return caches;
|
||||
}
|
||||
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the Ehcache cache again
|
||||
// in case the cache was added at runtime
|
||||
|
||||
Ehcache ehcache = cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
// reinitialize cache map
|
||||
afterPropertiesSet();
|
||||
cache = super.getCache(name);
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backing Ehcache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* @param cacheManager backing Ehcache {@link net.sf.ehcache.CacheManager}
|
||||
* Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*/
|
||||
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required");
|
||||
Status status = this.cacheManager.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
|
||||
String[] names = this.cacheManager.getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(this.cacheManager.getEhcache(name)));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the EhCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
Ehcache ehcache = this.cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
cache = new EhCacheCache(ehcache);
|
||||
addCache(cache);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,9 +41,9 @@ import org.springframework.util.ObjectUtils;
|
||||
* <p>This implementation caches attributes by method after they are first used.
|
||||
* If it is ever desirable to allow dynamic changing of cacheable attributes
|
||||
* (which is very unlikely), caching could be made configurable.
|
||||
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @see org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
|
||||
|
||||
@@ -67,6 +67,7 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
*/
|
||||
final Map<Object, CacheOperation> attributeCache = new ConcurrentHashMap<Object, CacheOperation>();
|
||||
|
||||
|
||||
/**
|
||||
* Determine the caching attribute for this method invocation.
|
||||
* <p>Defaults to the class's caching attribute if no method attribute is found.
|
||||
@@ -157,6 +158,7 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching attribute
|
||||
* for the given method, if any.
|
||||
@@ -183,8 +185,9 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default cache key for the CacheOperationDefinition cache.
|
||||
* Default cache key for the CacheOperation cache.
|
||||
*/
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
@@ -215,4 +218,5 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,27 +25,29 @@ import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
|
||||
* cache advice bean for methods that are cacheable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
|
||||
|
||||
private CacheOperationSource cacheDefinitionSource;
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
|
||||
@Override
|
||||
protected CacheOperationSource getCacheOperationSource() {
|
||||
return cacheDefinitionSource;
|
||||
return cacheOperationSource;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the cache operation attribute source which is used to find cache
|
||||
* attributes. This should usually be identical to the source reference
|
||||
* set on the cache interceptor itself.
|
||||
* @see CacheInterceptor#setCacheAttributeSource
|
||||
*/
|
||||
public void setCacheDefinitionSource(CacheOperationSource cacheDefinitionSource) {
|
||||
this.cacheDefinitionSource = cacheDefinitionSource;
|
||||
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,4 +61,5 @@ public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryP
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,12 +25,11 @@ import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.KeyGenerator;
|
||||
import org.springframework.cache.support.DefaultKeyGenerator;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -57,6 +56,8 @@ import org.springframework.util.StringUtils;
|
||||
* and <code>CacheDefinitionSource</code> are serializable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
@@ -64,26 +65,82 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private CacheOperationSource cacheDefinitionSource;
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
||||
|
||||
private volatile boolean initialized = false;
|
||||
private boolean initialized = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the CacheManager that this cache aspect should delegate to.
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheManager that this cache aspect delegates to.
|
||||
*/
|
||||
public CacheManager getCacheManager() {
|
||||
return this.cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple cache definition sources which are used to find the cache
|
||||
* attributes. Will build a CompositeCachingDefinitionSource for the given sources.
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
Assert.notEmpty(cacheDefinitionSources);
|
||||
this.cacheOperationSource = (cacheDefinitionSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheDefinitionSources) : cacheDefinitionSources[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CacheOperationSource for this cache aspect,
|
||||
* resolving applicable cache operations from annotations or the like.
|
||||
*/
|
||||
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource for this cache aspect.
|
||||
*/
|
||||
public CacheOperationSource getCacheOperationSource() {
|
||||
return this.cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the KeyGenerator for this cache aspect.
|
||||
* Default is {@link DefaultKeyGenerator}.
|
||||
*/
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyGenerator for this cache aspect,
|
||||
*/
|
||||
public KeyGenerator getKeyGenerator() {
|
||||
return this.keyGenerator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.cacheManager == null) {
|
||||
throw new IllegalStateException("Setting the property 'cacheManager' is required");
|
||||
throw new IllegalStateException("'cacheManager' is required");
|
||||
}
|
||||
if (this.cacheDefinitionSource == null) {
|
||||
if (this.cacheOperationSource == null) {
|
||||
throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: "
|
||||
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method to return a String representation of this Method
|
||||
* for use in logging. Can be overridden in subclasses to provide a
|
||||
@@ -98,62 +155,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||
}
|
||||
|
||||
public CacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
public CacheOperationSource getCacheDefinitionSource() {
|
||||
return cacheDefinitionSource;
|
||||
}
|
||||
|
||||
public KeyGenerator getKeyGenerator() {
|
||||
return keyGenerator;
|
||||
}
|
||||
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple cache definition sources which are used to find the cache
|
||||
* attributes. Will build a CompositeCachingDefinitionSource for the given sources.
|
||||
*/
|
||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
Assert.notEmpty(cacheDefinitionSources);
|
||||
this.cacheDefinitionSource = (cacheDefinitionSources.length > 1 ? new CompositeCacheOperationSource(
|
||||
cacheDefinitionSources) : cacheDefinitionSources[0]);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches(CacheOperation operation) {
|
||||
Set<String> cacheNames = operation.getCacheNames();
|
||||
|
||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = cacheManager.getCache(cacheName);
|
||||
Cache cache = this.cacheManager.getCache(cacheName);
|
||||
if (cache == null) {
|
||||
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
||||
}
|
||||
caches.add(cache);
|
||||
}
|
||||
|
||||
return caches;
|
||||
}
|
||||
|
||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
|
||||
return new CacheOperationContext(operation, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
protected Object execute(Callable<Object> invocation, Object target, Method method, Object[] args) throws Exception {
|
||||
// check whether aspect is enabled
|
||||
// to cope with cases where the AJ is pulled in automatically
|
||||
|
||||
if (!initialized) {
|
||||
if (!this.initialized) {
|
||||
return invocation.call();
|
||||
}
|
||||
|
||||
@@ -161,15 +185,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
// get backing class
|
||||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
||||
|
||||
if (targetClass == null && target != null) {
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
final CacheOperation cacheOp = getCacheDefinitionSource().getCacheOperation(method, targetClass);
|
||||
final CacheOperation cacheOp = getCacheOperationSource().getCacheOperation(method, targetClass);
|
||||
|
||||
Object retVal = null;
|
||||
|
||||
|
||||
// analyze caching information
|
||||
if (cacheOp != null) {
|
||||
CacheOperationContext context = getOperationContext(cacheOp, method, args, target, targetClass);
|
||||
@@ -179,11 +201,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
// check operation
|
||||
if (cacheOp instanceof CacheUpdateOperation) {
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for definition " + cacheOp);
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
||||
@@ -196,7 +216,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
for (Iterator<Cache> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) {
|
||||
Cache cache = iterator.next();
|
||||
Cache.ValueWrapper wrapper = cache.get(key);
|
||||
|
||||
if (wrapper != null) {
|
||||
cacheHit = true;
|
||||
retVal = wrapper.get();
|
||||
@@ -209,12 +228,12 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
+ method);
|
||||
}
|
||||
retVal = invocation.call();
|
||||
|
||||
// update all caches
|
||||
for (Cache cache : caches) {
|
||||
cache.put(key, retVal);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Key " + key + " found in cache, returning value " + retVal);
|
||||
}
|
||||
@@ -234,10 +253,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
if (evictOp.isCacheWide()) {
|
||||
cache.clear();
|
||||
if (log) {
|
||||
logger.trace("Invalidating entire cache for definition " + cacheOp + " on method "
|
||||
+ method);
|
||||
logger.trace("Invalidating entire cache for definition " + cacheOp +
|
||||
" on method " + method);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// check key
|
||||
if (key == null) {
|
||||
key = context.generateKey();
|
||||
@@ -250,9 +270,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + method + " for definition " + cacheOp);
|
||||
}
|
||||
@@ -262,19 +282,22 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
return invocation.call();
|
||||
}
|
||||
|
||||
|
||||
protected class CacheOperationContext {
|
||||
|
||||
private CacheOperation operation;
|
||||
private final CacheOperation operation;
|
||||
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
// context passed around to avoid multiple creations
|
||||
private final EvaluationContext evalContext;
|
||||
|
||||
private final KeyGenerator keyGenerator = CacheAspectSupport.this.keyGenerator;
|
||||
|
||||
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target,
|
||||
Class<?> targetClass) {
|
||||
this.operation = operation;
|
||||
@@ -286,39 +309,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the definition condition.
|
||||
*
|
||||
* @param operation
|
||||
* @return
|
||||
*/
|
||||
protected boolean hasConditionPassed() {
|
||||
if (StringUtils.hasText(operation.getCondition())) {
|
||||
return evaluator.condition(operation.getCondition(), method, evalContext);
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the key for the given caching definition.
|
||||
*
|
||||
* @param operation
|
||||
* @param method
|
||||
* method being invoked
|
||||
* @param objects
|
||||
* arguments passed during the method invocation
|
||||
* Computes the key for the given caching operation.
|
||||
* @return generated key (null if none can be generated)
|
||||
*/
|
||||
protected Object generateKey() {
|
||||
if (StringUtils.hasText(operation.getKey())) {
|
||||
return evaluator.key(operation.getKey(), method, evalContext);
|
||||
if (StringUtils.hasText(this.operation.getKey())) {
|
||||
return evaluator.key(this.operation.getKey(), this.method, this.evalContext);
|
||||
}
|
||||
|
||||
return keyGenerator.extract(target, method, args);
|
||||
return keyGenerator.extract(this.target, this.method, this.args);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches() {
|
||||
return caches;
|
||||
return this.caches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,27 +17,28 @@
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing an 'evict' operation.
|
||||
*
|
||||
* Class describing a cache 'evict' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheEvictOperation extends CacheOperation {
|
||||
|
||||
private boolean cacheWide = false;
|
||||
|
||||
public boolean isCacheWide() {
|
||||
return cacheWide;
|
||||
}
|
||||
|
||||
public void setCacheWide(boolean cacheWide) {
|
||||
this.cacheWide = cacheWide;
|
||||
}
|
||||
|
||||
public boolean isCacheWide() {
|
||||
return this.cacheWide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(",");
|
||||
sb.append(cacheWide);
|
||||
sb.append(this.cacheWide);
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,53 +20,62 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interface describing the root object used during the expression evaluation.
|
||||
*
|
||||
* Class describing the root object used during the expression evaluation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
interface CacheExpressionRootObject {
|
||||
class CacheExpressionRootObject {
|
||||
|
||||
/**
|
||||
* Returns the name of the method being cached.
|
||||
*
|
||||
* @return name of the cached method.
|
||||
*/
|
||||
String getMethodName();
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
/**
|
||||
* Returns the method being cached.
|
||||
*
|
||||
* @return method being cached
|
||||
*/
|
||||
Method getMethod();
|
||||
private final Method method;
|
||||
|
||||
/**
|
||||
* Returns the parameters for this invocation.
|
||||
*
|
||||
* @return params for this invocation.
|
||||
*/
|
||||
Object[] getParams();
|
||||
private final Object[] args;
|
||||
|
||||
/**
|
||||
* Returns the target instance being cached.
|
||||
*
|
||||
* @return target instance
|
||||
*/
|
||||
Object getTarget();
|
||||
private final Object target;
|
||||
|
||||
/**
|
||||
* Returns the target class.
|
||||
*
|
||||
* @return target class
|
||||
*/
|
||||
Class<?> getTargetClass();
|
||||
private final Class<?> targetClass;
|
||||
|
||||
|
||||
public CacheExpressionRootObject(
|
||||
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
Assert.notNull(method, "Method is required");
|
||||
Assert.notNull(targetClass, "targetClass is required");
|
||||
this.method = method;
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
this.args = args;
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
|
||||
public Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return this.method.getName();
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caches against which the method is executed.
|
||||
*
|
||||
* @return current cache
|
||||
*/
|
||||
Collection<Cache> getCaches();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,8 @@ import java.util.concurrent.Callable;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* AOP Alliance MethodInterceptor for declarative cache
|
||||
* management using the common Spring caching infrastructure
|
||||
@@ -34,8 +36,10 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
* in the correct order.
|
||||
*
|
||||
* <p>CacheInterceptors are thread-safe.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
|
||||
@@ -44,19 +48,18 @@ public class CacheInterceptor extends CacheAspectSupport implements MethodInterc
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
Callable<Object> aopAllianceInvocation = new Callable<Object>() {
|
||||
|
||||
public Object call() throws Exception {
|
||||
try {
|
||||
return invocation.proceed();
|
||||
} catch (Throwable th) {
|
||||
if (th instanceof Exception) {
|
||||
throw (Exception) th;
|
||||
}
|
||||
throw (Error) th;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
ReflectionUtils.rethrowException(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return execute(aopAllianceInvocation, invocation.getThis(), method, invocation.getArguments());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -115,13 +115,13 @@ public abstract class CacheOperation {
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("CacheDefinition[");
|
||||
result.append(name);
|
||||
result.append(this.name);
|
||||
result.append("] caches=");
|
||||
result.append(cacheNames);
|
||||
result.append(this.cacheNames);
|
||||
result.append(" | condition='");
|
||||
result.append(condition);
|
||||
result.append(this.condition);
|
||||
result.append("' | key='");
|
||||
result.append(key);
|
||||
result.append(this.key);
|
||||
result.append("'");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,24 +18,25 @@ package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* Interface used by CacheInterceptor. Implementations know
|
||||
* how to source cache operation attributes, whether from configuration,
|
||||
* metadata attributes at source level, or anywhere else.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheOperationSource {
|
||||
|
||||
/**
|
||||
* Return the cache operation definition for this method.
|
||||
* Return null if the method is not cacheable.
|
||||
* @param method method
|
||||
* @param targetClass target class. May be <code>null</code>, in which
|
||||
* case the declaring class of the method must be used.
|
||||
* Return the cache operation definition for this method,
|
||||
* or <code>null</code> if the method is not cacheable.
|
||||
* @param method the method to introspect
|
||||
* @param targetClass the target class (may be <code>null</code>,
|
||||
* in which case the declaring class of the method must be used)
|
||||
* @return {@link CacheOperation} the matching cache operation,
|
||||
* or <code>null</code> if none found
|
||||
*/
|
||||
CacheOperation getCacheOperation(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,10 +23,11 @@ import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Inner class that implements a Pointcut that matches if the underlying
|
||||
* {@link CacheOperationSource} has an attribute for a given method.
|
||||
* A Pointcut that matches if the underlying {@link CacheOperationSource}
|
||||
* has an attribute for a given method.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
@@ -65,4 +66,5 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut
|
||||
* To be implemented by subclasses.
|
||||
*/
|
||||
protected abstract CacheOperationSource getCacheOperationSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
|
||||
* @param cacheDefinitionSources cache definition sources
|
||||
*/
|
||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
this.cachingInterceptor.setCacheDefinitionSources(cacheDefinitionSources);
|
||||
this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,9 +17,10 @@
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing an 'update' operation.
|
||||
*
|
||||
* Class describing a cache 'update' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheUpdateOperation extends CacheOperation {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,40 +24,42 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Composite {@link CacheOperationSource} implementation that iterates
|
||||
* over a given array of {@link CacheOperationSource} instances.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CompositeCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
private final CacheOperationSource[] cacheDefinitionSources;
|
||||
private final CacheOperationSource[] cacheOperationSources;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new CompositeCachingDefinitionSource for the given sources.
|
||||
* @param cacheDefinitionSourcess the CacheDefinitionSource instances to combine
|
||||
* Create a new CompositeCacheOperationSource for the given sources.
|
||||
* @param cacheOperationSources the CacheOperationSource instances to combine
|
||||
*/
|
||||
public CompositeCacheOperationSource(CacheOperationSource[] cacheDefinitionSources) {
|
||||
Assert.notNull(cacheDefinitionSources, "cacheDefinitionSource array must not be null");
|
||||
this.cacheDefinitionSources = cacheDefinitionSources;
|
||||
public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty");
|
||||
this.cacheOperationSources = cacheOperationSources;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the CacheDefinitionSource instances that this
|
||||
* CompositeCachingDefinitionSource combines.
|
||||
* Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines.
|
||||
*/
|
||||
public final CacheOperationSource[] getCacheDefinitionSources() {
|
||||
return this.cacheDefinitionSources;
|
||||
public final CacheOperationSource[] getCacheOperationSources() {
|
||||
return this.cacheOperationSources;
|
||||
}
|
||||
|
||||
|
||||
public CacheOperation getCacheOperation(Method method, Class<?> targetClass) {
|
||||
for (CacheOperationSource source : cacheDefinitionSources) {
|
||||
for (CacheOperationSource source : this.cacheOperationSources) {
|
||||
CacheOperation definition = source.getCacheOperation(method, targetClass);
|
||||
if (definition != null) {
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of expression root object.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class DefaultCacheExpressionRootObject implements CacheExpressionRootObject {
|
||||
|
||||
private final Object target;
|
||||
private final Class<?> targetClass;
|
||||
private final String methodName;
|
||||
private final Method method;
|
||||
private final Collection<Cache> caches;
|
||||
private final Object[] args;
|
||||
|
||||
public DefaultCacheExpressionRootObject(Collection<Cache> caches, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
Assert.notNull(method, "method is required");
|
||||
Assert.notNull(targetClass, "targetClass is required");
|
||||
this.method = method;
|
||||
this.methodName = method.getName();
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
this.args = args;
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public Collection<Cache> getCaches() {
|
||||
return caches;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public Object[] getParams() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public Class<?> getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,17 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.support;
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cache.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
/**
|
||||
* Default key generator. Returns 0 if no param is given, the param itself if only one is given or a hash code computed
|
||||
* from all given params hash code. Uses a constant (53) for null objects.
|
||||
*
|
||||
* Default key generator. Returns 0 if no param is given, the param itself if
|
||||
* only one is given or a hash code computed from all given params hash code.
|
||||
* Uses a constant (53) for <code>null</code> objects.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultKeyGenerator implements KeyGenerator {
|
||||
|
||||
@@ -32,17 +34,14 @@ public class DefaultKeyGenerator implements KeyGenerator {
|
||||
if (params.length == 1) {
|
||||
return (params[0] == null ? 53 : params[0]);
|
||||
}
|
||||
|
||||
if (params.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hashCode = 17;
|
||||
|
||||
for (Object object : params) {
|
||||
hashCode = 31 * hashCode + (object == null ? 53 : object.hashCode());
|
||||
}
|
||||
|
||||
return Integer.valueOf(hashCode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,51 +27,55 @@ import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Utility class handling the SpEL expression parsing.
|
||||
* Meant to be used as a reusable, thread-safe component.
|
||||
*
|
||||
* Performs internal caching for performance reasons.
|
||||
*
|
||||
*
|
||||
* <p>Performs internal caching for performance reasons.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class ExpressionEvaluator {
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
// shared param discoverer since it caches data internally
|
||||
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
||||
|
||||
EvaluationContext createEvaluationContext(Collection<Cache> caches, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
DefaultCacheExpressionRootObject rootObject = new DefaultCacheExpressionRootObject(caches, method, args,
|
||||
target, targetClass);
|
||||
StandardEvaluationContext evaluationContext = new LazyParamAwareEvaluationContext(rootObject,
|
||||
paramNameDiscoverer, method, args, targetClass, targetMethodCache);
|
||||
|
||||
return evaluationContext;
|
||||
public EvaluationContext createEvaluationContext(
|
||||
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
CacheExpressionRootObject rootObject =
|
||||
new CacheExpressionRootObject(caches, method, args, target, targetClass);
|
||||
return new LazyParamAwareEvaluationContext(rootObject,
|
||||
this.paramNameDiscoverer, method, args, targetClass, this.targetMethodCache);
|
||||
}
|
||||
|
||||
boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression condExp = conditionCache.get(method);
|
||||
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression condExp = this.conditionCache.get(method);
|
||||
if (condExp == null) {
|
||||
condExp = parser.parseExpression(conditionExpression);
|
||||
conditionCache.put(method, condExp);
|
||||
condExp = this.parser.parseExpression(conditionExpression);
|
||||
this.conditionCache.put(method, condExp);
|
||||
}
|
||||
return condExp.getValue(evalContext, boolean.class);
|
||||
}
|
||||
|
||||
Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression keyExp = keyCache.get(method);
|
||||
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression keyExp = this.keyCache.get(method);
|
||||
if (keyExp == null) {
|
||||
keyExp = parser.parseExpression(keyExpression);
|
||||
keyCache.put(method, keyExp);
|
||||
keyExp = this.parser.parseExpression(keyExpression);
|
||||
this.keyCache.put(method, keyExp);
|
||||
}
|
||||
return keyExp.getValue(evalContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,17 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache;
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Cache 'key' extractor. Used for creating a key based on the given method
|
||||
* (used as context) and its parameters.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface KeyGenerator {
|
||||
|
||||
Object extract(Object target, Method method, Object... params);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,22 +28,28 @@ import org.springframework.util.ObjectUtils;
|
||||
* Evaluation context class that adds a method parameters as SpEL variables,
|
||||
* in a lazy manner. The lazy nature eliminates unneeded parsing of classes
|
||||
* byte code for parameter discovery.
|
||||
*
|
||||
* To limit the creation of objects, an ugly constructor is used (rather then a
|
||||
* dedicated 'closure'-like class for deferred execution).
|
||||
*
|
||||
*
|
||||
* <p>To limit the creation of objects, an ugly constructor is used (rather then
|
||||
* a dedicated 'closure'-like class for deferred execution).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private final ParameterNameDiscoverer paramDiscoverer;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
private Class<?> targetClass;
|
||||
private Map<Method, Method> methodCache;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Map<Method, Method> methodCache;
|
||||
|
||||
private boolean paramLoaded = false;
|
||||
|
||||
|
||||
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
||||
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) {
|
||||
super(rootObject);
|
||||
@@ -55,6 +61,7 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
this.methodCache = methodCache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the param information only when needed.
|
||||
*/
|
||||
@@ -64,42 +71,41 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
|
||||
if (!paramLoaded) {
|
||||
paramLoaded = true;
|
||||
if (!this.paramLoaded) {
|
||||
loadArgsAsVariables();
|
||||
this.paramLoaded = true;
|
||||
variable = super.lookupVariable(name);
|
||||
}
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
private void loadArgsAsVariables() {
|
||||
// shortcut if no args need to be loaded
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
if (ObjectUtils.isEmpty(this.args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method targetMethod = methodCache.get(method);
|
||||
Method targetMethod = this.methodCache.get(this.method);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = method;
|
||||
targetMethod = this.method;
|
||||
}
|
||||
methodCache.put(method, targetMethod);
|
||||
this.methodCache.put(this.method, targetMethod);
|
||||
}
|
||||
|
||||
// save arguments as indexed variables
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
super.setVariable("p" + i, args[i]);
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
setVariable("p" + i, this.args[i]);
|
||||
}
|
||||
|
||||
String[] parameterNames = paramDiscoverer.getParameterNames(targetMethod);
|
||||
String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod);
|
||||
// save parameter names (if discovered)
|
||||
if (parameterNames != null) {
|
||||
for (int i = 0; i < parameterNames.length; i++) {
|
||||
super.setVariable(parameterNames[i], args[i]);
|
||||
setVariable(parameterNames[i], this.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,57 +29,50 @@ import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class implementing the common CacheManager methods. Useful for 'static' environments where the
|
||||
* backing caches do not change.
|
||||
*
|
||||
* Abstract base class implementing the common CacheManager methods.
|
||||
* Useful for 'static' environments where the backing caches do not change.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
|
||||
|
||||
// fast lookup by name map
|
||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
||||
private Collection<String> names;
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
private Set<String> cacheNames = new LinkedHashSet<String>();
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Collection<Cache> cacheSet = loadCaches();
|
||||
|
||||
Assert.notEmpty(cacheSet);
|
||||
|
||||
caches.clear();
|
||||
Collection<Cache> caches = loadCaches();
|
||||
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
|
||||
this.cacheMap.clear();
|
||||
|
||||
// preserve the initial order of the cache names
|
||||
Set<String> cacheNames = new LinkedHashSet<String>(cacheSet.size());
|
||||
|
||||
for (Cache cache : cacheSet) {
|
||||
caches.put(cache.getName(), cache);
|
||||
cacheNames.add(cache.getName());
|
||||
for (Cache cache : caches) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
|
||||
names = Collections.unmodifiableSet(cacheNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the caches into the cache manager. Occurs at startup.
|
||||
* The returned collection should not be null.
|
||||
*
|
||||
* @param caches the collection of caches handled by the manager
|
||||
*/
|
||||
protected abstract Collection<Cache> loadCaches();
|
||||
|
||||
/**
|
||||
* Returns the internal cache map.
|
||||
*
|
||||
* @return internal cache map
|
||||
*/
|
||||
protected final ConcurrentMap<String, Cache> getCacheMap() {
|
||||
return caches;
|
||||
protected final void addCache(Cache cache) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
|
||||
public Cache getCache(String name) {
|
||||
return caches.get(name);
|
||||
return this.cacheMap.get(name);
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
return names;
|
||||
return Collections.unmodifiableSet(this.cacheNames);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the caches for this cache manager. Occurs at startup.
|
||||
* The returned collection must not be null.
|
||||
*/
|
||||
protected abstract Collection<Cache> loadCaches();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,57 +29,59 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Composite {@link CacheManager} implementation that iterates
|
||||
* over a given collection of {@link CacheManager} instances.
|
||||
*
|
||||
*
|
||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||
* the cache declarations without a backing store.
|
||||
*
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
|
||||
private List<CacheManager> cacheManagers;
|
||||
private boolean noOpManager = false;
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (noOpManager) {
|
||||
cacheManagers.add(new NoOpCacheManager());
|
||||
}
|
||||
}
|
||||
private boolean fallbackToNoOpCache = false;
|
||||
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = null;
|
||||
for (CacheManager cacheManager : cacheManagers) {
|
||||
cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (CacheManager manager : cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableCollection(names);
|
||||
}
|
||||
|
||||
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
|
||||
Assert.notEmpty(cacheManagers, "non-null/empty array required");
|
||||
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
|
||||
this.cacheManagers = new ArrayList<CacheManager>();
|
||||
this.cacheManagers.addAll(cacheManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a {@link NoOpCacheManager} will be added at the end of the manager lists.
|
||||
* Any cache requests not handled by the configured cache managers will be automatically handled
|
||||
* by the {@link NoOpCacheManager}.
|
||||
*
|
||||
* @param add whether a {@link NoOpCacheManager} instance will be added or not
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||
* In this case, any <code>getCache</code> requests not handled by the configured cache managers will
|
||||
* be automatically handled by the {@link NoOpCacheManager} (and hence never return <code>null</code>).
|
||||
*/
|
||||
public void setAddNoOpCache(boolean add) {
|
||||
this.noOpManager = add;
|
||||
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||
this.fallbackToNoOpCache = fallbackToNoOpCache;
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.fallbackToNoOpCache) {
|
||||
this.cacheManagers.add(new NoOpCacheManager());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Cache getCache(String name) {
|
||||
for (CacheManager cacheManager : this.cacheManagers) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (CacheManager manager : this.cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,11 +29,12 @@ import org.springframework.cache.CacheManager;
|
||||
/**
|
||||
* A basic, no operation {@link CacheManager} implementation suitable for disabling caching,
|
||||
* typically used for backing cache declarations without an actual backing store.
|
||||
*
|
||||
* Will simply accept any items into the cache not actually storing them.
|
||||
*
|
||||
* @see CompositeCacheManager
|
||||
*
|
||||
* <p>Will simply accept any items into the cache not actually storing them.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
* @see CompositeCacheManager
|
||||
*/
|
||||
public class NoOpCacheManager implements CacheManager {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,21 +21,26 @@ import java.util.Collection;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Simple cache manager working against a given collection of caches. Useful for testing or simple
|
||||
* caching declarations.
|
||||
*
|
||||
* Simple cache manager working against a given collection of caches.
|
||||
* Useful for testing or simple caching declarations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SimpleCacheManager extends AbstractCacheManager {
|
||||
|
||||
private Collection<Cache> caches;
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
return caches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the collection of Cache instances to use for this CacheManager.
|
||||
*/
|
||||
public void setCaches(Collection<Cache> caches) {
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,19 +19,21 @@ package org.springframework.cache.support;
|
||||
import org.springframework.cache.Cache.ValueWrapper;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link org.springframework.cache.Cache.ValueWrapper}.
|
||||
*
|
||||
* Straightforward implementation of {@link org.springframework.cache.Cache.ValueWrapper}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultValueWrapper implements ValueWrapper {
|
||||
public class ValueWrapperImpl implements ValueWrapper {
|
||||
|
||||
private final Object value;
|
||||
|
||||
public DefaultValueWrapper(Object value) {
|
||||
public ValueWrapperImpl(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return value;
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user