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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,73 +16,67 @@
|
|||||||
|
|
||||||
package org.springframework.cache;
|
package org.springframework.cache;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines the common cache operations.
|
* Interface that defines the common cache operations.
|
||||||
*
|
*
|
||||||
* <b>Note:</b> Due to the generic use of caching, it is recommended that
|
* <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
|
* 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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public interface Cache {
|
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.
|
* A (wrapper) object representing a cache value.
|
||||||
*/
|
*/
|
||||||
interface ValueWrapper {
|
interface ValueWrapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the actual value in the cache.
|
* Return the actual value in the cache.
|
||||||
*
|
|
||||||
* @return cache value
|
|
||||||
*/
|
*/
|
||||||
Object get();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity managing {@link Cache}s.
|
* A manager for a set of {@link Cache}s.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public interface CacheManager {
|
public interface CacheManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cache associated with the given name.
|
* Return the cache associated with the given name.
|
||||||
*
|
* @param name cache identifier (must not be <code>null</code>)
|
||||||
* @param name cache identifier - cannot be null
|
* @return associated cache, or <code>null</code> if none is found
|
||||||
* @return associated cache or null if none is found
|
|
||||||
*/
|
*/
|
||||||
Cache getCache(String name);
|
Cache getCache(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of the caches known by this cache manager.
|
* Return a collection of the caches known by this cache manager.
|
||||||
*
|
* @return names of caches known by the cache manager.
|
||||||
* @return names of caches known by the cache manager.
|
|
||||||
*/
|
*/
|
||||||
Collection<String> getCacheNames();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* This class may also serve as base class for a custom CacheOperationSource.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements
|
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource
|
||||||
Serializable {
|
implements Serializable {
|
||||||
|
|
||||||
private final boolean publicMethodsOnly;
|
private final boolean publicMethodsOnly;
|
||||||
|
|
||||||
private final Set<CacheAnnotationParser> annotationParsers;
|
private final Set<CacheAnnotationParser> annotationParsers;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a default AnnotationCacheOperationSource, supporting
|
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||||
* public methods that carry the <code>Cacheable</code> and <code>CacheEvict</code>
|
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||||
* annotations.
|
|
||||||
*/
|
*/
|
||||||
public AnnotationCacheOperationSource() {
|
public AnnotationCacheOperationSource() {
|
||||||
this(true);
|
this(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a custom AnnotationCacheOperationSource, supporting
|
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||||
* public methods that carry the <code>Cacheable</code> and
|
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||||
* <code>CacheEvict</code> annotations.
|
|
||||||
*
|
|
||||||
* @param publicMethodsOnly whether to support only annotated public methods
|
* @param publicMethodsOnly whether to support only annotated public methods
|
||||||
* typically for use with proxy-based AOP), or protected/private methods as well
|
* typically for use with proxy-based AOP), or protected/private methods as well
|
||||||
* (typically used with AspectJ class weaving)
|
* (typically used with AspectJ class weaving)
|
||||||
@@ -67,7 +66,7 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
|||||||
public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
|
public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
|
||||||
this.publicMethodsOnly = publicMethodsOnly;
|
this.publicMethodsOnly = publicMethodsOnly;
|
||||||
this.annotationParsers = new LinkedHashSet<CacheAnnotationParser>(1);
|
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;
|
this.annotationParsers = parsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CacheOperation findCacheOperation(Class<?> clazz) {
|
protected CacheOperation findCacheOperation(Class<?> clazz) {
|
||||||
return determineCacheOperation(clazz);
|
return determineCacheOperation(clazz);
|
||||||
@@ -120,4 +120,5 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
|||||||
protected boolean allowPublicMethodsOnly() {
|
protected boolean allowPublicMethodsOnly() {
|
||||||
return this.publicMethodsOnly;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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}.
|
* {@link Cacheable} or {@link CacheEvict}.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public interface CacheAnnotationParser {
|
public interface CacheAnnotationParser {
|
||||||
|
|
||||||
@@ -43,4 +44,5 @@ public interface CacheAnnotationParser {
|
|||||||
* @see AnnotationCacheOperationSource#determineCacheOperation
|
* @see AnnotationCacheOperationSource#determineCacheOperation
|
||||||
*/
|
*/
|
||||||
CacheOperation parseCacheAnnotation(AnnotatedElement ae);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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)
|
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||||
* a cache invalidate operation.
|
* a cache invalidate operation.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@Target( { ElementType.METHOD, ElementType.TYPE })
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Inherited
|
@Inherited
|
||||||
@Documented
|
@Documented
|
||||||
@@ -44,24 +45,22 @@ public @interface CacheEvict {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||||
* <p/>
|
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||||
* Default is "" meaning all method parameters are considered as a key.
|
|
||||||
*/
|
*/
|
||||||
String key() default "";
|
String key() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||||
* <p/>
|
* <p>Default is "", meaning the method is always cached.
|
||||||
* Default is "" meaning the method is always cached.
|
|
||||||
*/
|
*/
|
||||||
String condition() default "";
|
String condition() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not all the entries inside the cache(s) are removed or not. By
|
* 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.
|
* default, only the value under the associated key is removed.
|
||||||
*
|
* <p>Note that specifying setting this parameter to true and specifying a
|
||||||
* Note that specifying setting this parameter to true and specifying a
|
|
||||||
* {@link CacheKey key} is not allowed.
|
* {@link CacheKey key} is not allowed.
|
||||||
*/
|
*/
|
||||||
boolean allEntries() default false;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* 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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@@ -55,4 +57,4 @@ public @interface Cacheable {
|
|||||||
*/
|
*/
|
||||||
String condition() default "";
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,86 +17,129 @@
|
|||||||
package org.springframework.cache.concurrent;
|
package org.springframework.cache.concurrent;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
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+
|
* Simple {@link Cache} implementation based on the core JDK
|
||||||
* java.util.concurrent package. Useful for testing or simple caching scenarios.
|
* <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 Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class ConcurrentMapCache implements Cache {
|
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 static final Object NULL_HOLDER = new NullHolder();
|
||||||
private final ConcurrentMap store;
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
private final ConcurrentMap<Object, Object> store;
|
||||||
|
|
||||||
private final boolean allowNullValues;
|
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) {
|
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.name = name;
|
||||||
|
this.store = store;
|
||||||
this.allowNullValues = allowNullValues;
|
this.allowNullValues = allowNullValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAllowNullValues() {
|
public String getName() {
|
||||||
return allowNullValues;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConcurrentMap getNativeCache() {
|
public ConcurrentMap getNativeCache() {
|
||||||
return store;
|
return this.store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public boolean isAllowNullValues() {
|
||||||
store.clear();
|
return this.allowNullValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueWrapper get(Object key) {
|
public ValueWrapper get(Object key) {
|
||||||
Object v = store.get(key);
|
Object value = this.store.get(key);
|
||||||
return (v != null ? new DefaultValueWrapper(filterNull(v)) : null);
|
return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(Object key, Object value) {
|
public void put(Object key, Object value) {
|
||||||
if (allowNullValues && value == null) {
|
this.store.put(key, toStoreValue(value));
|
||||||
Map map = store;
|
|
||||||
map.put(key, NULL_HOLDER);
|
|
||||||
} else {
|
|
||||||
store.put(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void evict(Object key) {
|
public void evict(Object key) {
|
||||||
store.remove(key);
|
this.store.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object filterNull(Object val) {
|
public void clear() {
|
||||||
if (allowNullValues && val == NULL_HOLDER) {
|
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 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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 Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class ConcurrentMapCacheFactoryBean implements FactoryBean<ConcurrentMapCache>, BeanNameAware,
|
public class ConcurrentMapCacheFactoryBean
|
||||||
InitializingBean {
|
implements FactoryBean<ConcurrentMapCache>, BeanNameAware, InitializingBean {
|
||||||
|
|
||||||
private String name = "";
|
private String name = "";
|
||||||
|
|
||||||
|
private ConcurrentMap<Object, Object> store;
|
||||||
|
|
||||||
|
private boolean allowNullValues = true;
|
||||||
|
|
||||||
private ConcurrentMapCache cache;
|
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() {
|
public Class<?> getObjectType() {
|
||||||
return (cache != null ? cache.getClass() : ConcurrentMapCache.class);
|
return ConcurrentMapCache.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSingleton() {
|
public boolean isSingleton() {
|
||||||
return true;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.cache.config;
|
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.aop.config.AopNamespaceUtils;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
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.annotation.AnnotationCacheOperationSource;
|
||||||
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
|
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
|
||||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
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}
|
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||||
@@ -43,6 +44,7 @@ import org.w3c.dom.Element;
|
|||||||
* will result in class-based proxies being created.
|
* will result in class-based proxies being created.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
@@ -111,7 +113,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
|||||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) {
|
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) {
|
||||||
Object eleSource = parserContext.extractSource(element);
|
Object eleSource = parserContext.extractSource(element);
|
||||||
|
|
||||||
// Create the CacheDefinitionSource definition.
|
// Create the CacheOperationSource definition.
|
||||||
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class);
|
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class);
|
||||||
sourceDef.setSource(eleSource);
|
sourceDef.setSource(eleSource);
|
||||||
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
@@ -122,14 +124,14 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
|||||||
interceptorDef.setSource(eleSource);
|
interceptorDef.setSource(eleSource);
|
||||||
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
registerCacheManagerProperty(element, interceptorDef);
|
registerCacheManagerProperty(element, interceptorDef);
|
||||||
interceptorDef.getPropertyValues().add("cacheDefinitionSources", new RuntimeBeanReference(sourceName));
|
interceptorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||||
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||||
|
|
||||||
// Create the CacheAdvisor definition.
|
// Create the CacheAdvisor definition.
|
||||||
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
|
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
|
||||||
advisorDef.setSource(eleSource);
|
advisorDef.setSource(eleSource);
|
||||||
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
advisorDef.getPropertyValues().add("cacheDefinitionSource", new RuntimeBeanReference(sourceName));
|
advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||||
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
||||||
if (element.hasAttribute("order")) {
|
if (element.hasAttribute("order")) {
|
||||||
advisorDef.getPropertyValues().add("order", element.getAttribute("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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* Spring cache management facilities.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 net.sf.ehcache.Status;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.support.DefaultValueWrapper;
|
import org.springframework.cache.support.ValueWrapperImpl;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class EhCacheCache implements Cache {
|
public class EhCacheCache implements Cache {
|
||||||
|
|
||||||
private final Ehcache cache;
|
private final Ehcache cache;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link EhCacheCache} instance.
|
* Create an {@link EhCacheCache} instance.
|
||||||
*
|
|
||||||
* @param ehcache backing Ehcache instance
|
* @param ehcache backing Ehcache instance
|
||||||
*/
|
*/
|
||||||
public EhCacheCache(Ehcache ehcache) {
|
public EhCacheCache(Ehcache ehcache) {
|
||||||
Assert.notNull(ehcache, "non null ehcache required");
|
Assert.notNull(ehcache, "Ehcache must not be null");
|
||||||
Status status = ehcache.getStatus();
|
Status status = ehcache.getStatus();
|
||||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status), "an 'alive' ehcache is required - current cache is "
|
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||||
+ status.toString());
|
"An 'alive' Ehcache is required - current cache is " + status.toString());
|
||||||
this.cache = ehcache;
|
this.cache = ehcache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return cache.getName();
|
return this.cache.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ehcache getNativeCache() {
|
public Ehcache getNativeCache() {
|
||||||
return cache;
|
return this.cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
cache.removeAll();
|
this.cache.removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueWrapper get(Object key) {
|
public ValueWrapper get(Object key) {
|
||||||
Element element = cache.get(key);
|
Element element = this.cache.get(key);
|
||||||
return (element != null ? new DefaultValueWrapper(element.getObjectValue()) : null);
|
return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(Object key, Object value) {
|
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) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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 Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class EhCacheCacheManager extends AbstractCacheManager {
|
public class EhCacheCacheManager extends AbstractCacheManager {
|
||||||
|
|
||||||
private net.sf.ehcache.CacheManager cacheManager;
|
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}.
|
* Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||||
*
|
|
||||||
* @param cacheManager backing Ehcache {@link net.sf.ehcache.CacheManager}
|
|
||||||
*/
|
*/
|
||||||
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||||
this.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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* <p>This implementation caches attributes by method after they are first used.
|
||||||
* If it is ever desirable to allow dynamic changing of cacheable attributes
|
* If it is ever desirable to allow dynamic changing of cacheable attributes
|
||||||
* (which is very unlikely), caching could be made configurable.
|
* (which is very unlikely), caching could be made configurable.
|
||||||
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
* @see org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
|
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>();
|
final Map<Object, CacheOperation> attributeCache = new ConcurrentHashMap<Object, CacheOperation>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the caching attribute for this method invocation.
|
* Determine the caching attribute for this method invocation.
|
||||||
* <p>Defaults to the class's caching attribute if no method attribute is found.
|
* <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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses need to implement this to return the caching attribute
|
* Subclasses need to implement this to return the caching attribute
|
||||||
* for the given method, if any.
|
* for the given method, if any.
|
||||||
@@ -183,8 +185,9 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default cache key for the CacheOperationDefinition cache.
|
* Default cache key for the CacheOperation cache.
|
||||||
*/
|
*/
|
||||||
private static class DefaultCacheKey {
|
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);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* cache advice bean for methods that are cacheable.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
|
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
|
||||||
|
|
||||||
private CacheOperationSource cacheDefinitionSource;
|
private CacheOperationSource cacheOperationSource;
|
||||||
|
|
||||||
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
|
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
|
||||||
@Override
|
@Override
|
||||||
protected CacheOperationSource getCacheOperationSource() {
|
protected CacheOperationSource getCacheOperationSource() {
|
||||||
return cacheDefinitionSource;
|
return cacheOperationSource;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the cache operation attribute source which is used to find cache
|
* Set the cache operation attribute source which is used to find cache
|
||||||
* attributes. This should usually be identical to the source reference
|
* attributes. This should usually be identical to the source reference
|
||||||
* set on the cache interceptor itself.
|
* set on the cache interceptor itself.
|
||||||
* @see CacheInterceptor#setCacheAttributeSource
|
* @see CacheInterceptor#setCacheAttributeSource
|
||||||
*/
|
*/
|
||||||
public void setCacheDefinitionSource(CacheOperationSource cacheDefinitionSource) {
|
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
|
||||||
this.cacheDefinitionSource = cacheDefinitionSource;
|
this.cacheOperationSource = cacheOperationSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,4 +61,5 @@ public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryP
|
|||||||
public Pointcut getPointcut() {
|
public Pointcut getPointcut() {
|
||||||
return this.pointcut;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.aop.framework.AopProxyUtils;
|
import org.springframework.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.KeyGenerator;
|
|
||||||
import org.springframework.cache.support.DefaultKeyGenerator;
|
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -57,6 +56,8 @@ import org.springframework.util.StringUtils;
|
|||||||
* and <code>CacheDefinitionSource</code> are serializable.
|
* and <code>CacheDefinitionSource</code> are serializable.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public abstract class CacheAspectSupport implements InitializingBean {
|
public abstract class CacheAspectSupport implements InitializingBean {
|
||||||
|
|
||||||
@@ -64,26 +65,82 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
|
|
||||||
private CacheManager cacheManager;
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
private CacheOperationSource cacheDefinitionSource;
|
private CacheOperationSource cacheOperationSource;
|
||||||
|
|
||||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||||
|
|
||||||
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
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() {
|
public void afterPropertiesSet() {
|
||||||
if (this.cacheManager == null) {
|
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: "
|
throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: "
|
||||||
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to return a String representation of this Method
|
* Convenience method to return a String representation of this Method
|
||||||
* for use in logging. Can be overridden in subclasses to provide a
|
* for use in logging. Can be overridden in subclasses to provide a
|
||||||
@@ -98,62 +155,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
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) {
|
protected Collection<Cache> getCaches(CacheOperation operation) {
|
||||||
Set<String> cacheNames = operation.getCacheNames();
|
Set<String> cacheNames = operation.getCacheNames();
|
||||||
|
|
||||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||||
|
|
||||||
for (String cacheName : cacheNames) {
|
for (String cacheName : cacheNames) {
|
||||||
Cache cache = cacheManager.getCache(cacheName);
|
Cache cache = this.cacheManager.getCache(cacheName);
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
||||||
}
|
}
|
||||||
caches.add(cache);
|
caches.add(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return caches;
|
return caches;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
||||||
Object target, Class<?> targetClass) {
|
Object target, Class<?> targetClass) {
|
||||||
|
|
||||||
return new CacheOperationContext(operation, method, args, target, targetClass);
|
return new CacheOperationContext(operation, method, args, target, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object execute(Callable<Object> invocation, Object target, Method method, Object[] args) throws Exception {
|
protected Object execute(Callable<Object> invocation, Object target, Method method, Object[] args) throws Exception {
|
||||||
// check whether aspect is enabled
|
// check whether aspect is enabled
|
||||||
// to cope with cases where the AJ is pulled in automatically
|
// to cope with cases where the AJ is pulled in automatically
|
||||||
|
if (!this.initialized) {
|
||||||
if (!initialized) {
|
|
||||||
return invocation.call();
|
return invocation.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,15 +185,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
|
|
||||||
// get backing class
|
// get backing class
|
||||||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
||||||
|
|
||||||
if (targetClass == null && target != null) {
|
if (targetClass == null && target != null) {
|
||||||
targetClass = target.getClass();
|
targetClass = target.getClass();
|
||||||
}
|
}
|
||||||
final CacheOperation cacheOp = getCacheDefinitionSource().getCacheOperation(method, targetClass);
|
final CacheOperation cacheOp = getCacheOperationSource().getCacheOperation(method, targetClass);
|
||||||
|
|
||||||
Object retVal = null;
|
Object retVal = null;
|
||||||
|
|
||||||
|
|
||||||
// analyze caching information
|
// analyze caching information
|
||||||
if (cacheOp != null) {
|
if (cacheOp != null) {
|
||||||
CacheOperationContext context = getOperationContext(cacheOp, method, args, target, targetClass);
|
CacheOperationContext context = getOperationContext(cacheOp, method, args, target, targetClass);
|
||||||
@@ -179,11 +201,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
// check operation
|
// check operation
|
||||||
if (cacheOp instanceof CacheUpdateOperation) {
|
if (cacheOp instanceof CacheUpdateOperation) {
|
||||||
Object key = context.generateKey();
|
Object key = context.generateKey();
|
||||||
|
|
||||||
if (log) {
|
if (log) {
|
||||||
logger.trace("Computed cache key " + key + " for definition " + cacheOp);
|
logger.trace("Computed cache key " + key + " for definition " + cacheOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
"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;) {
|
for (Iterator<Cache> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) {
|
||||||
Cache cache = iterator.next();
|
Cache cache = iterator.next();
|
||||||
Cache.ValueWrapper wrapper = cache.get(key);
|
Cache.ValueWrapper wrapper = cache.get(key);
|
||||||
|
|
||||||
if (wrapper != null) {
|
if (wrapper != null) {
|
||||||
cacheHit = true;
|
cacheHit = true;
|
||||||
retVal = wrapper.get();
|
retVal = wrapper.get();
|
||||||
@@ -209,12 +228,12 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
+ method);
|
+ method);
|
||||||
}
|
}
|
||||||
retVal = invocation.call();
|
retVal = invocation.call();
|
||||||
|
|
||||||
// update all caches
|
// update all caches
|
||||||
for (Cache cache : caches) {
|
for (Cache cache : caches) {
|
||||||
cache.put(key, retVal);
|
cache.put(key, retVal);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (log) {
|
if (log) {
|
||||||
logger.trace("Key " + key + " found in cache, returning value " + retVal);
|
logger.trace("Key " + key + " found in cache, returning value " + retVal);
|
||||||
}
|
}
|
||||||
@@ -234,10 +253,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
if (evictOp.isCacheWide()) {
|
if (evictOp.isCacheWide()) {
|
||||||
cache.clear();
|
cache.clear();
|
||||||
if (log) {
|
if (log) {
|
||||||
logger.trace("Invalidating entire cache for definition " + cacheOp + " on method "
|
logger.trace("Invalidating entire cache for definition " + cacheOp +
|
||||||
+ method);
|
" on method " + method);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// check key
|
// check key
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
key = context.generateKey();
|
key = context.generateKey();
|
||||||
@@ -250,9 +270,9 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (log) {
|
if (log) {
|
||||||
logger.trace("Cache condition failed on method " + method + " for definition " + cacheOp);
|
logger.trace("Cache condition failed on method " + method + " for definition " + cacheOp);
|
||||||
}
|
}
|
||||||
@@ -262,19 +282,22 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
return invocation.call();
|
return invocation.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class CacheOperationContext {
|
protected class CacheOperationContext {
|
||||||
|
|
||||||
private CacheOperation operation;
|
private final CacheOperation operation;
|
||||||
|
|
||||||
private final Collection<Cache> caches;
|
private final Collection<Cache> caches;
|
||||||
|
|
||||||
private final Object target;
|
private final Object target;
|
||||||
|
|
||||||
private final Method method;
|
private final Method method;
|
||||||
|
|
||||||
private final Object[] args;
|
private final Object[] args;
|
||||||
|
|
||||||
// context passed around to avoid multiple creations
|
// context passed around to avoid multiple creations
|
||||||
private final EvaluationContext evalContext;
|
private final EvaluationContext evalContext;
|
||||||
|
|
||||||
private final KeyGenerator keyGenerator = CacheAspectSupport.this.keyGenerator;
|
|
||||||
|
|
||||||
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target,
|
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target,
|
||||||
Class<?> targetClass) {
|
Class<?> targetClass) {
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
@@ -286,39 +309,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
|||||||
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
|
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the definition condition.
|
|
||||||
*
|
|
||||||
* @param operation
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected boolean hasConditionPassed() {
|
protected boolean hasConditionPassed() {
|
||||||
if (StringUtils.hasText(operation.getCondition())) {
|
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||||
return evaluator.condition(operation.getCondition(), method, evalContext);
|
return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the key for the given caching definition.
|
* Computes the key for the given caching operation.
|
||||||
*
|
|
||||||
* @param operation
|
|
||||||
* @param method
|
|
||||||
* method being invoked
|
|
||||||
* @param objects
|
|
||||||
* arguments passed during the method invocation
|
|
||||||
* @return generated key (null if none can be generated)
|
* @return generated key (null if none can be generated)
|
||||||
*/
|
*/
|
||||||
protected Object generateKey() {
|
protected Object generateKey() {
|
||||||
if (StringUtils.hasText(operation.getKey())) {
|
if (StringUtils.hasText(this.operation.getKey())) {
|
||||||
return evaluator.key(operation.getKey(), method, evalContext);
|
return evaluator.key(this.operation.getKey(), this.method, this.evalContext);
|
||||||
}
|
}
|
||||||
|
return keyGenerator.extract(this.target, this.method, this.args);
|
||||||
return keyGenerator.extract(target, method, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection<Cache> getCaches() {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,27 +17,28 @@
|
|||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class describing an 'evict' operation.
|
* Class describing a cache 'evict' operation.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class CacheEvictOperation extends CacheOperation {
|
public class CacheEvictOperation extends CacheOperation {
|
||||||
|
|
||||||
private boolean cacheWide = false;
|
private boolean cacheWide = false;
|
||||||
|
|
||||||
public boolean isCacheWide() {
|
|
||||||
return cacheWide;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCacheWide(boolean cacheWide) {
|
public void setCacheWide(boolean cacheWide) {
|
||||||
this.cacheWide = cacheWide;
|
this.cacheWide = cacheWide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCacheWide() {
|
||||||
|
return this.cacheWide;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StringBuilder getOperationDescription() {
|
protected StringBuilder getOperationDescription() {
|
||||||
StringBuilder sb = super.getOperationDescription();
|
StringBuilder sb = super.getOperationDescription();
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
sb.append(cacheWide);
|
sb.append(this.cacheWide);
|
||||||
return sb;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
interface CacheExpressionRootObject {
|
class CacheExpressionRootObject {
|
||||||
|
|
||||||
/**
|
private final Collection<Cache> caches;
|
||||||
* Returns the name of the method being cached.
|
|
||||||
*
|
|
||||||
* @return name of the cached method.
|
|
||||||
*/
|
|
||||||
String getMethodName();
|
|
||||||
|
|
||||||
/**
|
private final Method method;
|
||||||
* Returns the method being cached.
|
|
||||||
*
|
|
||||||
* @return method being cached
|
|
||||||
*/
|
|
||||||
Method getMethod();
|
|
||||||
|
|
||||||
/**
|
private final Object[] args;
|
||||||
* Returns the parameters for this invocation.
|
|
||||||
*
|
|
||||||
* @return params for this invocation.
|
|
||||||
*/
|
|
||||||
Object[] getParams();
|
|
||||||
|
|
||||||
/**
|
private final Object target;
|
||||||
* Returns the target instance being cached.
|
|
||||||
*
|
|
||||||
* @return target instance
|
|
||||||
*/
|
|
||||||
Object getTarget();
|
|
||||||
|
|
||||||
/**
|
private final Class<?> targetClass;
|
||||||
* Returns the target class.
|
|
||||||
*
|
|
||||||
* @return target class
|
public CacheExpressionRootObject(
|
||||||
*/
|
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||||
Class<?> getTargetClass();
|
|
||||||
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AOP Alliance MethodInterceptor for declarative cache
|
* AOP Alliance MethodInterceptor for declarative cache
|
||||||
* management using the common Spring caching infrastructure
|
* management using the common Spring caching infrastructure
|
||||||
@@ -34,8 +36,10 @@ import org.aopalliance.intercept.MethodInvocation;
|
|||||||
* in the correct order.
|
* in the correct order.
|
||||||
*
|
*
|
||||||
* <p>CacheInterceptors are thread-safe.
|
* <p>CacheInterceptors are thread-safe.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
|
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
|
||||||
@@ -44,19 +48,18 @@ public class CacheInterceptor extends CacheAspectSupport implements MethodInterc
|
|||||||
Method method = invocation.getMethod();
|
Method method = invocation.getMethod();
|
||||||
|
|
||||||
Callable<Object> aopAllianceInvocation = new Callable<Object>() {
|
Callable<Object> aopAllianceInvocation = new Callable<Object>() {
|
||||||
|
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
try {
|
try {
|
||||||
return invocation.proceed();
|
return invocation.proceed();
|
||||||
} catch (Throwable th) {
|
}
|
||||||
if (th instanceof Exception) {
|
catch (Throwable ex) {
|
||||||
throw (Exception) th;
|
ReflectionUtils.rethrowException(ex);
|
||||||
}
|
return null;
|
||||||
throw (Error) th;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return execute(aopAllianceInvocation, invocation.getThis(), method, invocation.getArguments());
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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() {
|
protected StringBuilder getOperationDescription() {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
result.append("CacheDefinition[");
|
result.append("CacheDefinition[");
|
||||||
result.append(name);
|
result.append(this.name);
|
||||||
result.append("] caches=");
|
result.append("] caches=");
|
||||||
result.append(cacheNames);
|
result.append(this.cacheNames);
|
||||||
result.append(" | condition='");
|
result.append(" | condition='");
|
||||||
result.append(condition);
|
result.append(this.condition);
|
||||||
result.append("' | key='");
|
result.append("' | key='");
|
||||||
result.append(key);
|
result.append(this.key);
|
||||||
result.append("'");
|
result.append("'");
|
||||||
return result;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface used by CacheInterceptor. Implementations know
|
* Interface used by CacheInterceptor. Implementations know
|
||||||
* how to source cache operation attributes, whether from configuration,
|
* how to source cache operation attributes, whether from configuration,
|
||||||
* metadata attributes at source level, or anywhere else.
|
* metadata attributes at source level, or anywhere else.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public interface CacheOperationSource {
|
public interface CacheOperationSource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the cache operation definition for this method.
|
* Return the cache operation definition for this method,
|
||||||
* Return null if the method is not cacheable.
|
* or <code>null</code> if the method is not cacheable.
|
||||||
* @param method method
|
* @param method the method to introspect
|
||||||
* @param targetClass target class. May be <code>null</code>, in which
|
* @param targetClass the target class (may be <code>null</code>,
|
||||||
* case the declaring class of the method must be used.
|
* in which case the declaring class of the method must be used)
|
||||||
* @return {@link CacheOperation} the matching cache operation,
|
* @return {@link CacheOperation} the matching cache operation,
|
||||||
* or <code>null</code> if none found
|
* or <code>null</code> if none found
|
||||||
*/
|
*/
|
||||||
CacheOperation getCacheOperation(Method method, Class<?> targetClass);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inner class that implements a Pointcut that matches if the underlying
|
* A Pointcut that matches if the underlying {@link CacheOperationSource}
|
||||||
* {@link CacheOperationSource} has an attribute for a given method.
|
* has an attribute for a given method.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||||
@@ -65,4 +66,5 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut
|
|||||||
* To be implemented by subclasses.
|
* To be implemented by subclasses.
|
||||||
*/
|
*/
|
||||||
protected abstract CacheOperationSource getCacheOperationSource();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* @param cacheDefinitionSources cache definition sources
|
||||||
*/
|
*/
|
||||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,9 +17,10 @@
|
|||||||
package org.springframework.cache.interceptor;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class describing an 'update' operation.
|
* Class describing a cache 'update' operation.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class CacheUpdateOperation extends CacheOperation {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* Composite {@link CacheOperationSource} implementation that iterates
|
||||||
* over a given array of {@link CacheOperationSource} instances.
|
* over a given array of {@link CacheOperationSource} instances.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class CompositeCacheOperationSource implements CacheOperationSource, Serializable {
|
public class CompositeCacheOperationSource implements CacheOperationSource, Serializable {
|
||||||
|
|
||||||
private final CacheOperationSource[] cacheDefinitionSources;
|
private final CacheOperationSource[] cacheOperationSources;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new CompositeCachingDefinitionSource for the given sources.
|
* Create a new CompositeCacheOperationSource for the given sources.
|
||||||
* @param cacheDefinitionSourcess the CacheDefinitionSource instances to combine
|
* @param cacheOperationSources the CacheOperationSource instances to combine
|
||||||
*/
|
*/
|
||||||
public CompositeCacheOperationSource(CacheOperationSource[] cacheDefinitionSources) {
|
public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) {
|
||||||
Assert.notNull(cacheDefinitionSources, "cacheDefinitionSource array must not be null");
|
Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty");
|
||||||
this.cacheDefinitionSources = cacheDefinitionSources;
|
this.cacheOperationSources = cacheOperationSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the CacheDefinitionSource instances that this
|
* Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines.
|
||||||
* CompositeCachingDefinitionSource combines.
|
|
||||||
*/
|
*/
|
||||||
public final CacheOperationSource[] getCacheDefinitionSources() {
|
public final CacheOperationSource[] getCacheOperationSources() {
|
||||||
return this.cacheDefinitionSources;
|
return this.cacheOperationSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CacheOperation getCacheOperation(Method method, Class<?> targetClass) {
|
public CacheOperation getCacheOperation(Method method, Class<?> targetClass) {
|
||||||
for (CacheOperationSource source : cacheDefinitionSources) {
|
for (CacheOperationSource source : this.cacheOperationSources) {
|
||||||
CacheOperation definition = source.getCacheOperation(method, targetClass);
|
CacheOperation definition = source.getCacheOperation(method, targetClass);
|
||||||
if (definition != null) {
|
if (definition != null) {
|
||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,17 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.cache.support;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
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
|
* Default key generator. Returns 0 if no param is given, the param itself if
|
||||||
* from all given params hash code. Uses a constant (53) for null objects.
|
* 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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class DefaultKeyGenerator implements KeyGenerator {
|
public class DefaultKeyGenerator implements KeyGenerator {
|
||||||
|
|
||||||
@@ -32,17 +34,14 @@ public class DefaultKeyGenerator implements KeyGenerator {
|
|||||||
if (params.length == 1) {
|
if (params.length == 1) {
|
||||||
return (params[0] == null ? 53 : params[0]);
|
return (params[0] == null ? 53 : params[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.length == 0) {
|
if (params.length == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashCode = 17;
|
int hashCode = 17;
|
||||||
|
|
||||||
for (Object object : params) {
|
for (Object object : params) {
|
||||||
hashCode = 31 * hashCode + (object == null ? 53 : object.hashCode());
|
hashCode = 31 * hashCode + (object == null ? 53 : object.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Integer.valueOf(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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.EvaluationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class handling the SpEL expression parsing.
|
* Utility class handling the SpEL expression parsing.
|
||||||
* Meant to be used as a reusable, thread-safe component.
|
* 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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
class ExpressionEvaluator {
|
class ExpressionEvaluator {
|
||||||
|
|
||||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
// shared param discoverer since it caches data internally
|
// shared param discoverer since it caches data internally
|
||||||
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||||
|
|
||||||
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>();
|
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>();
|
||||||
|
|
||||||
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
||||||
|
|
||||||
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
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) {
|
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||||
Expression condExp = conditionCache.get(method);
|
Expression condExp = this.conditionCache.get(method);
|
||||||
if (condExp == null) {
|
if (condExp == null) {
|
||||||
condExp = parser.parseExpression(conditionExpression);
|
condExp = this.parser.parseExpression(conditionExpression);
|
||||||
conditionCache.put(method, condExp);
|
this.conditionCache.put(method, condExp);
|
||||||
}
|
}
|
||||||
return condExp.getValue(evalContext, boolean.class);
|
return condExp.getValue(evalContext, boolean.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||||
Expression keyExp = keyCache.get(method);
|
Expression keyExp = this.keyCache.get(method);
|
||||||
if (keyExp == null) {
|
if (keyExp == null) {
|
||||||
keyExp = parser.parseExpression(keyExpression);
|
keyExp = this.parser.parseExpression(keyExpression);
|
||||||
keyCache.put(method, keyExp);
|
this.keyCache.put(method, keyExp);
|
||||||
}
|
}
|
||||||
return keyExp.getValue(evalContext);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,17 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.cache;
|
package org.springframework.cache.interceptor;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache 'key' extractor. Used for creating a key based on the given method
|
* Cache 'key' extractor. Used for creating a key based on the given method
|
||||||
* (used as context) and its parameters.
|
* (used as context) and its parameters.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public interface KeyGenerator {
|
public interface KeyGenerator {
|
||||||
|
|
||||||
Object extract(Object target, Method method, Object... params);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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,
|
* Evaluation context class that adds a method parameters as SpEL variables,
|
||||||
* in a lazy manner. The lazy nature eliminates unneeded parsing of classes
|
* in a lazy manner. The lazy nature eliminates unneeded parsing of classes
|
||||||
* byte code for parameter discovery.
|
* byte code for parameter discovery.
|
||||||
*
|
*
|
||||||
* To limit the creation of objects, an ugly constructor is used (rather then a
|
* <p>To limit the creation of objects, an ugly constructor is used (rather then
|
||||||
* dedicated 'closure'-like class for deferred execution).
|
* a dedicated 'closure'-like class for deferred execution).
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||||
|
|
||||||
private final ParameterNameDiscoverer paramDiscoverer;
|
private final ParameterNameDiscoverer paramDiscoverer;
|
||||||
|
|
||||||
private final Method method;
|
private final Method method;
|
||||||
|
|
||||||
private final Object[] args;
|
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;
|
private boolean paramLoaded = false;
|
||||||
|
|
||||||
|
|
||||||
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
||||||
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) {
|
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) {
|
||||||
super(rootObject);
|
super(rootObject);
|
||||||
@@ -55,6 +61,7 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
|||||||
this.methodCache = methodCache;
|
this.methodCache = methodCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the param information only when needed.
|
* Load the param information only when needed.
|
||||||
*/
|
*/
|
||||||
@@ -64,42 +71,41 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
|||||||
if (variable != null) {
|
if (variable != null) {
|
||||||
return variable;
|
return variable;
|
||||||
}
|
}
|
||||||
|
if (!this.paramLoaded) {
|
||||||
if (!paramLoaded) {
|
|
||||||
paramLoaded = true;
|
|
||||||
loadArgsAsVariables();
|
loadArgsAsVariables();
|
||||||
|
this.paramLoaded = true;
|
||||||
variable = super.lookupVariable(name);
|
variable = super.lookupVariable(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return variable;
|
return variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadArgsAsVariables() {
|
private void loadArgsAsVariables() {
|
||||||
// shortcut if no args need to be loaded
|
// shortcut if no args need to be loaded
|
||||||
if (ObjectUtils.isEmpty(args)) {
|
if (ObjectUtils.isEmpty(this.args)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Method targetMethod = methodCache.get(method);
|
Method targetMethod = this.methodCache.get(this.method);
|
||||||
if (targetMethod == null) {
|
if (targetMethod == null) {
|
||||||
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
|
||||||
if (targetMethod == null) {
|
if (targetMethod == null) {
|
||||||
targetMethod = method;
|
targetMethod = this.method;
|
||||||
}
|
}
|
||||||
methodCache.put(method, targetMethod);
|
this.methodCache.put(this.method, targetMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save arguments as indexed variables
|
// save arguments as indexed variables
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < this.args.length; i++) {
|
||||||
super.setVariable("p" + i, args[i]);
|
setVariable("p" + i, this.args[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] parameterNames = paramDiscoverer.getParameterNames(targetMethod);
|
String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod);
|
||||||
// save parameter names (if discovered)
|
// save parameter names (if discovered)
|
||||||
if (parameterNames != null) {
|
if (parameterNames != null) {
|
||||||
for (int i = 0; i < parameterNames.length; i++) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class implementing the common CacheManager methods. Useful for 'static' environments where the
|
* Abstract base class implementing the common CacheManager methods.
|
||||||
* backing caches do not change.
|
* Useful for 'static' environments where the backing caches do not change.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
|
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
|
||||||
|
|
||||||
// fast lookup by name map
|
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
|
||||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
|
||||||
private Collection<String> names;
|
private Set<String> cacheNames = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
Collection<Cache> cacheSet = loadCaches();
|
Collection<Cache> caches = loadCaches();
|
||||||
|
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
|
||||||
Assert.notEmpty(cacheSet);
|
this.cacheMap.clear();
|
||||||
|
|
||||||
caches.clear();
|
|
||||||
|
|
||||||
// preserve the initial order of the cache names
|
// preserve the initial order of the cache names
|
||||||
Set<String> cacheNames = new LinkedHashSet<String>(cacheSet.size());
|
for (Cache cache : caches) {
|
||||||
|
this.cacheMap.put(cache.getName(), cache);
|
||||||
for (Cache cache : cacheSet) {
|
this.cacheNames.add(cache.getName());
|
||||||
caches.put(cache.getName(), cache);
|
|
||||||
cacheNames.add(cache.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
names = Collections.unmodifiableSet(cacheNames);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected final void addCache(Cache cache) {
|
||||||
* Loads the caches into the cache manager. Occurs at startup.
|
this.cacheMap.put(cache.getName(), cache);
|
||||||
* The returned collection should not be null.
|
this.cacheNames.add(cache.getName());
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cache getCache(String name) {
|
public Cache getCache(String name) {
|
||||||
return caches.get(name);
|
return this.cacheMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getCacheNames() {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* Composite {@link CacheManager} implementation that iterates
|
||||||
* over a given collection of {@link CacheManager} instances.
|
* over a given collection of {@link CacheManager} instances.
|
||||||
*
|
*
|
||||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||||
* the cache declarations without a backing store.
|
* the cache declarations without a backing store.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||||
|
|
||||||
private List<CacheManager> cacheManagers;
|
private List<CacheManager> cacheManagers;
|
||||||
private boolean noOpManager = false;
|
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
private boolean fallbackToNoOpCache = false;
|
||||||
if (noOpManager) {
|
|
||||||
cacheManagers.add(new NoOpCacheManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
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 = new ArrayList<CacheManager>();
|
||||||
this.cacheManagers.addAll(cacheManagers);
|
this.cacheManagers.addAll(cacheManagers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether a {@link NoOpCacheManager} will be added at the end of the manager lists.
|
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||||
* Any cache requests not handled by the configured cache managers will be automatically handled
|
* In this case, any <code>getCache</code> requests not handled by the configured cache managers will
|
||||||
* by the {@link NoOpCacheManager}.
|
* be automatically handled by the {@link NoOpCacheManager} (and hence never return <code>null</code>).
|
||||||
*
|
|
||||||
* @param add whether a {@link NoOpCacheManager} instance will be added or not
|
|
||||||
*/
|
*/
|
||||||
public void setAddNoOpCache(boolean add) {
|
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||||
this.noOpManager = add;
|
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,
|
* A basic, no operation {@link CacheManager} implementation suitable for disabling caching,
|
||||||
* typically used for backing cache declarations without an actual backing store.
|
* typically used for backing cache declarations without an actual backing store.
|
||||||
*
|
*
|
||||||
* Will simply accept any items into the cache not actually storing them.
|
* <p>Will simply accept any items into the cache not actually storing them.
|
||||||
*
|
*
|
||||||
* @see CompositeCacheManager
|
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
|
* @see CompositeCacheManager
|
||||||
*/
|
*/
|
||||||
public class NoOpCacheManager implements CacheManager {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
import org.springframework.cache.Cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple cache manager working against a given collection of caches. Useful for testing or simple
|
* Simple cache manager working against a given collection of caches.
|
||||||
* caching declarations.
|
* Useful for testing or simple caching declarations.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class SimpleCacheManager extends AbstractCacheManager {
|
public class SimpleCacheManager extends AbstractCacheManager {
|
||||||
|
|
||||||
private Collection<Cache> caches;
|
private Collection<Cache> caches;
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected Collection<Cache> loadCaches() {
|
* Specify the collection of Cache instances to use for this CacheManager.
|
||||||
return caches;
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public void setCaches(Collection<Cache> caches) {
|
public void setCaches(Collection<Cache> caches) {
|
||||||
this.caches = 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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
|
* @author Costin Leau
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public class DefaultValueWrapper implements ValueWrapper {
|
public class ValueWrapperImpl implements ValueWrapper {
|
||||||
|
|
||||||
private final Object value;
|
private final Object value;
|
||||||
|
|
||||||
public DefaultValueWrapper(Object value) {
|
public ValueWrapperImpl(Object value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get() {
|
public Object get() {
|
||||||
return value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.cache.support.NoOpCacheManager;
|
import org.springframework.cache.support.NoOpCacheManager;
|
||||||
|
|
||||||
public class NoOpCacheManagerTest {
|
public class NoOpCacheManagerTests {
|
||||||
|
|
||||||
private CacheManager manager;
|
private CacheManager manager;
|
||||||
|
|
||||||
@@ -20,16 +20,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.vendor.AbstractNativeCacheTest;
|
import org.springframework.cache.vendor.AbstractNativeCacheTests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class ConcurrentCacheTest extends AbstractNativeCacheTest<ConcurrentMap<Object, Object>> {
|
public class ConcurrentCacheTests extends AbstractNativeCacheTests<ConcurrentMap<Object, Object>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Cache createCache(ConcurrentMap<Object, Object> nativeCache) {
|
protected Cache createCache(ConcurrentMap<Object, Object> nativeCache) {
|
||||||
return new ConcurrentMapCache(nativeCache, CACHE_NAME, true);
|
return new ConcurrentMapCache(CACHE_NAME, nativeCache, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
*/
|
||||||
|
public class ConcurrentMapCacheManagerTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicMode() {
|
||||||
|
CacheManager cm = new ConcurrentMapCacheManager();
|
||||||
|
Cache cache1 = cm.getCache("c1");
|
||||||
|
assertTrue(cache1 instanceof ConcurrentMapCache);
|
||||||
|
Cache cache1again = cm.getCache("c1");
|
||||||
|
assertSame(cache1again, cache1);
|
||||||
|
Cache cache2 = cm.getCache("c2");
|
||||||
|
assertTrue(cache2 instanceof ConcurrentMapCache);
|
||||||
|
Cache cache2again = cm.getCache("c2");
|
||||||
|
assertSame(cache2again, cache2);
|
||||||
|
Cache cache3 = cm.getCache("c3");
|
||||||
|
assertTrue(cache3 instanceof ConcurrentMapCache);
|
||||||
|
Cache cache3again = cm.getCache("c3");
|
||||||
|
assertSame(cache3again, cache3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStaticMode() {
|
||||||
|
ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2");
|
||||||
|
Cache cache1 = cm.getCache("c1");
|
||||||
|
assertTrue(cache1 instanceof ConcurrentMapCache);
|
||||||
|
Cache cache1again = cm.getCache("c1");
|
||||||
|
assertSame(cache1again, cache1);
|
||||||
|
Cache cache2 = cm.getCache("c2");
|
||||||
|
assertTrue(cache2 instanceof ConcurrentMapCache);
|
||||||
|
Cache cache2again = cm.getCache("c2");
|
||||||
|
assertSame(cache2again, cache2);
|
||||||
|
Cache cache3 = cm.getCache("c3");
|
||||||
|
assertNull(cache3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAnnotationTest {
|
public abstract class AbstractAnnotationTests {
|
||||||
|
|
||||||
protected ApplicationContext ctx;
|
protected ApplicationContext ctx;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ package org.springframework.cache.config;
|
|||||||
/**
|
/**
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class AnnotationNamespaceDrivenTest extends AbstractAnnotationTest {
|
public class AnnotationNamespaceDrivenTests extends AbstractAnnotationTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getConfig() {
|
protected String getConfig() {
|
||||||
@@ -20,7 +20,7 @@ package org.springframework.cache.config;
|
|||||||
/**
|
/**
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class AnnotationTest extends AbstractAnnotationTest {
|
public class AnnotationTests extends AbstractAnnotationTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getConfig() {
|
protected String getConfig() {
|
||||||
@@ -22,14 +22,14 @@ import net.sf.ehcache.Element;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.vendor.AbstractNativeCacheTest;
|
import org.springframework.cache.vendor.AbstractNativeCacheTests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration test for EhCache cache.
|
* Integration test for EhCache cache.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class EhCacheCacheTest extends AbstractNativeCacheTest<Ehcache> {
|
public class EhCacheCacheTests extends AbstractNativeCacheTests<Ehcache> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Ehcache createNativeCache() throws Exception {
|
protected Ehcache createNativeCache() throws Exception {
|
||||||
@@ -27,7 +27,7 @@ import org.springframework.cache.Cache;
|
|||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractNativeCacheTest<T> {
|
public abstract class AbstractNativeCacheTests<T> {
|
||||||
|
|
||||||
protected T nativeCache;
|
protected T nativeCache;
|
||||||
protected Cache cache;
|
protected Cache cache;
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
<bean id="cacheInterceptor" class="org.springframework.cache.interceptor.CacheInterceptor">
|
<bean id="cacheInterceptor" class="org.springframework.cache.interceptor.CacheInterceptor">
|
||||||
<property name="cacheManager" ref="cacheManager"/>
|
<property name="cacheManager" ref="cacheManager"/>
|
||||||
<property name="cacheDefinitionSources" ref="annotationSource"/>
|
<property name="cacheOperationSources" ref="annotationSource"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="advisor" class="org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor">
|
<bean id="advisor" class="org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor">
|
||||||
<property name="cacheDefinitionSource" ref="annotationSource"/>
|
<property name="cacheOperationSource" ref="annotationSource"/>
|
||||||
<property name="adviceBeanName" value="cacheInterceptor"/>
|
<property name="adviceBeanName" value="cacheInterceptor"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user