Convert cache package line endings from CRLF => LF
Unfortunately creates a large diff due to whitespace changes as well as false attribution of authorship from a git/svn 'blame' perspective. Be sure to perform diffs using `git diff -w` or `svn diff -w` when reviewing recent changes to these sources to ignore all whitespace.
This commit is contained in:
parent
f9879b762b
commit
a252a285e2
|
|
@ -1,82 +1,82 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface that defines the common cache operations.
|
||||
*
|
||||
* <b>Note:</b> Due to the generic use of caching, it is recommended that
|
||||
* implementations allow storage of <tt>null</tt> values (for example to
|
||||
* cache methods that return <code>null</code>).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface Cache {
|
||||
|
||||
/**
|
||||
* Return the cache name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the the underlying native cache provider.
|
||||
*/
|
||||
Object getNativeCache();
|
||||
|
||||
/**
|
||||
* Return the value to which this cache maps the specified key. Returns
|
||||
* <code>null</code> if the cache contains no mapping for this key.
|
||||
* @param key key whose associated value is to be returned.
|
||||
* @return the value to which this cache maps the specified key,
|
||||
* or <code>null</code> if the cache contains no mapping for this key
|
||||
*/
|
||||
ValueWrapper get(Object key);
|
||||
|
||||
/**
|
||||
* Associate the specified value with the specified key in this cache.
|
||||
* <p>If the cache previously contained a mapping for this key, the old
|
||||
* value is replaced by the specified value.
|
||||
* @param key the key with which the specified value is to be associated
|
||||
* @param value the value to be associated with the specified key
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* Evict the mapping for this key from this cache if it is present.
|
||||
* @param key the key whose mapping is to be removed from the cache
|
||||
*/
|
||||
void evict(Object key);
|
||||
|
||||
/**
|
||||
* Remove all mappings from the cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
/**
|
||||
* A (wrapper) object representing a cache value.
|
||||
*/
|
||||
interface ValueWrapper {
|
||||
|
||||
/**
|
||||
* Return the actual value in the cache.
|
||||
*/
|
||||
Object get();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface that defines the common cache operations.
|
||||
*
|
||||
* <b>Note:</b> Due to the generic use of caching, it is recommended that
|
||||
* implementations allow storage of <tt>null</tt> values (for example to
|
||||
* cache methods that return {@code null}).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface Cache {
|
||||
|
||||
/**
|
||||
* Return the cache name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the the underlying native cache provider.
|
||||
*/
|
||||
Object getNativeCache();
|
||||
|
||||
/**
|
||||
* Return the value to which this cache maps the specified key. Returns
|
||||
* <code>null</code> if the cache contains no mapping for this key.
|
||||
* @param key key whose associated value is to be returned.
|
||||
* @return the value to which this cache maps the specified key,
|
||||
* or <code>null</code> if the cache contains no mapping for this key
|
||||
*/
|
||||
ValueWrapper get(Object key);
|
||||
|
||||
/**
|
||||
* Associate the specified value with the specified key in this cache.
|
||||
* <p>If the cache previously contained a mapping for this key, the old
|
||||
* value is replaced by the specified value.
|
||||
* @param key the key with which the specified value is to be associated
|
||||
* @param value the value to be associated with the specified key
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* Evict the mapping for this key from this cache if it is present.
|
||||
* @param key the key whose mapping is to be removed from the cache
|
||||
*/
|
||||
void evict(Object key);
|
||||
|
||||
/**
|
||||
* Remove all mappings from the cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
/**
|
||||
* A (wrapper) object representing a cache value.
|
||||
*/
|
||||
interface ValueWrapper {
|
||||
|
||||
/**
|
||||
* Return the actual value in the cache.
|
||||
*/
|
||||
Object get();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,42 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A manager for a set of {@link Cache}s.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheManager {
|
||||
|
||||
/**
|
||||
* Return the cache associated with the given name.
|
||||
* @param name cache identifier (must not be <code>null</code>)
|
||||
* @return associated cache, or <code>null</code> if none is found
|
||||
*/
|
||||
Cache getCache(String name);
|
||||
|
||||
/**
|
||||
* Return a collection of the caches known by this cache manager.
|
||||
* @return names of caches known by the cache manager.
|
||||
*/
|
||||
Collection<String> getCacheNames();
|
||||
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A manager for a set of {@link Cache}s.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheManager {
|
||||
|
||||
/**
|
||||
* Return the cache associated with the given name.
|
||||
* @param name cache identifier (must not be {@code null})
|
||||
* @return associated cache, or {@code null} if none is found
|
||||
*/
|
||||
Cache getCache(String name);
|
||||
|
||||
/**
|
||||
* Return a collection of the caches known by this cache manager.
|
||||
* @return names of caches known by the cache manager.
|
||||
*/
|
||||
Collection<String> getCacheNames();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,130 +1,130 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.cache.interceptor.AbstractFallbackCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of the {@link org.springframework.cache.interceptor.CacheOperationSource}
|
||||
* interface for working with caching metadata in JDK 1.5+ annotation format.
|
||||
*
|
||||
* <p>This class reads Spring's JDK 1.5+ {@link Cacheable}, {@link CachePut} and {@link CacheEvict}
|
||||
* annotations and exposes corresponding caching operation definition to Spring's cache infrastructure.
|
||||
* This class may also serve as base class for a custom CacheOperationSource.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource
|
||||
implements Serializable {
|
||||
|
||||
private final boolean publicMethodsOnly;
|
||||
|
||||
private final Set<CacheAnnotationParser> annotationParsers;
|
||||
|
||||
|
||||
/**
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
*/
|
||||
public AnnotationCacheOperationSource() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
* @param publicMethodsOnly whether to support only annotated public methods
|
||||
* typically for use with proxy-based AOP), or protected/private methods as well
|
||||
* (typically used with AspectJ class weaving)
|
||||
*/
|
||||
public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
|
||||
this.publicMethodsOnly = publicMethodsOnly;
|
||||
this.annotationParsers = new LinkedHashSet<CacheAnnotationParser>(1);
|
||||
this.annotationParsers.add(new SpringCacheAnnotationParser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom AnnotationCacheOperationSource.
|
||||
* @param annotationParsers the CacheAnnotationParser to use
|
||||
*/
|
||||
public AnnotationCacheOperationSource(CacheAnnotationParser... annotationParsers) {
|
||||
this.publicMethodsOnly = true;
|
||||
Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified");
|
||||
Set<CacheAnnotationParser> parsers = new LinkedHashSet<CacheAnnotationParser>(annotationParsers.length);
|
||||
Collections.addAll(parsers, annotationParsers);
|
||||
this.annotationParsers = parsers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
|
||||
return determineCacheOperations(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<CacheOperation> findCacheOperations(Method method) {
|
||||
return determineCacheOperations(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the cache operation definition for the given method or class.
|
||||
* <p>This implementation delegates to configured
|
||||
* {@link CacheAnnotationParser CacheAnnotationParsers}
|
||||
* for parsing known annotations into Spring's metadata attribute class.
|
||||
* Returns <code>null</code> if it's not cacheable.
|
||||
* <p>Can be overridden to support custom annotations that carry caching metadata.
|
||||
* @param ae the annotated method or class
|
||||
* @return CacheOperation the configured caching operation,
|
||||
* or <code>null</code> if none was found
|
||||
*/
|
||||
protected Collection<CacheOperation> determineCacheOperations(AnnotatedElement ae) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
|
||||
Collection<CacheOperation> annOps = annotationParser.parseCacheAnnotations(ae);
|
||||
if (annOps != null) {
|
||||
if (ops == null) {
|
||||
ops = new ArrayList<CacheOperation>();
|
||||
}
|
||||
ops.addAll(annOps);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, only public methods can be made cacheable.
|
||||
*/
|
||||
@Override
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return this.publicMethodsOnly;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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 java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.cache.interceptor.AbstractFallbackCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of the {@link org.springframework.cache.interceptor.CacheOperationSource}
|
||||
* interface for working with caching metadata in JDK 1.5+ annotation format.
|
||||
*
|
||||
* <p>This class reads Spring's JDK 1.5+ {@link Cacheable}, {@link CachePut} and {@link CacheEvict}
|
||||
* annotations and exposes corresponding caching operation definition to Spring's cache infrastructure.
|
||||
* This class may also serve as base class for a custom CacheOperationSource.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource
|
||||
implements Serializable {
|
||||
|
||||
private final boolean publicMethodsOnly;
|
||||
|
||||
private final Set<CacheAnnotationParser> annotationParsers;
|
||||
|
||||
|
||||
/**
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
*/
|
||||
public AnnotationCacheOperationSource() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default AnnotationCacheOperationSource, supporting public methods
|
||||
* that carry the <code>Cacheable</code> and <code>CacheEvict</code> annotations.
|
||||
* @param publicMethodsOnly whether to support only annotated public methods
|
||||
* typically for use with proxy-based AOP), or protected/private methods as well
|
||||
* (typically used with AspectJ class weaving)
|
||||
*/
|
||||
public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
|
||||
this.publicMethodsOnly = publicMethodsOnly;
|
||||
this.annotationParsers = new LinkedHashSet<CacheAnnotationParser>(1);
|
||||
this.annotationParsers.add(new SpringCacheAnnotationParser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom AnnotationCacheOperationSource.
|
||||
* @param annotationParsers the CacheAnnotationParser to use
|
||||
*/
|
||||
public AnnotationCacheOperationSource(CacheAnnotationParser... annotationParsers) {
|
||||
this.publicMethodsOnly = true;
|
||||
Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified");
|
||||
Set<CacheAnnotationParser> parsers = new LinkedHashSet<CacheAnnotationParser>(annotationParsers.length);
|
||||
Collections.addAll(parsers, annotationParsers);
|
||||
this.annotationParsers = parsers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
|
||||
return determineCacheOperations(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<CacheOperation> findCacheOperations(Method method) {
|
||||
return determineCacheOperations(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the cache operation definition for the given method or class.
|
||||
* <p>This implementation delegates to configured
|
||||
* {@link CacheAnnotationParser CacheAnnotationParsers}
|
||||
* for parsing known annotations into Spring's metadata attribute class.
|
||||
* Returns <code>null</code> if it's not cacheable.
|
||||
* <p>Can be overridden to support custom annotations that carry caching metadata.
|
||||
* @param ae the annotated method or class
|
||||
* @return CacheOperation the configured caching operation,
|
||||
* or <code>null</code> if none was found
|
||||
*/
|
||||
protected Collection<CacheOperation> determineCacheOperations(AnnotatedElement ae) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
|
||||
Collection<CacheOperation> annOps = annotationParser.parseCacheAnnotations(ae);
|
||||
if (annOps != null) {
|
||||
if (ops == null) {
|
||||
ops = new ArrayList<CacheOperation>();
|
||||
}
|
||||
ops.addAll(annOps);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, only public methods can be made cacheable.
|
||||
*/
|
||||
@Override
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return this.publicMethodsOnly;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,47 @@
|
|||
/*
|
||||
* 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.lang.reflect.AnnotatedElement;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface for parsing known caching annotation types.
|
||||
* {@link AnnotationCacheDefinitionSource} delegates to such
|
||||
* parsers for supporting specific annotation types such as Spring's own
|
||||
* {@link Cacheable}, {@link CachePut} or {@link CacheEvict}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheAnnotationParser {
|
||||
|
||||
/**
|
||||
* Parses the cache definition for the given method or class,
|
||||
* based on a known annotation type.
|
||||
* <p>This essentially parses a known cache annotation into Spring's
|
||||
* metadata attribute class. Returns <code>null</code> if the method/class
|
||||
* is not cacheable.
|
||||
* @param ae the annotated method or class
|
||||
* @return CacheOperation the configured caching operation,
|
||||
* or <code>null</code> if none was found
|
||||
* @see AnnotationCacheOperationSource#determineCacheOperation
|
||||
*/
|
||||
Collection<CacheOperation> parseCacheAnnotations(AnnotatedElement ae);
|
||||
}
|
||||
/*
|
||||
* 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.lang.reflect.AnnotatedElement;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
|
||||
/**
|
||||
* Strategy interface for parsing known caching annotation types.
|
||||
* {@link AnnotationCacheDefinitionSource} delegates to such
|
||||
* parsers for supporting specific annotation types such as Spring's own
|
||||
* {@link Cacheable}, {@link CachePut} or {@link CacheEvict}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheAnnotationParser {
|
||||
|
||||
/**
|
||||
* Parses the cache definition for the given method or class,
|
||||
* based on a known annotation type.
|
||||
* <p>This essentially parses a known cache annotation into Spring's
|
||||
* metadata attribute class. Returns {@code null} if the method/class
|
||||
* is not cacheable.
|
||||
* @param ae the annotated method or class
|
||||
* @return CacheOperation the configured caching operation,
|
||||
* or {@code null} if none was found
|
||||
* @see AnnotationCacheOperationSource#determineCacheOperation
|
||||
*/
|
||||
Collection<CacheOperation> parseCacheAnnotations(AnnotatedElement ae);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,44 @@
|
|||
/*
|
||||
* Copyright 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Group annotation for multiple cache annotations (of different or the same type).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CacheDefinitions {
|
||||
|
||||
Cacheable[] cacheable() default {};
|
||||
|
||||
CachePut[] put() default {};
|
||||
|
||||
CacheEvict[] evict() default {};
|
||||
}
|
||||
/*
|
||||
* 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Group annotation for multiple cache annotations (of different or the same type).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CacheDefinitions {
|
||||
|
||||
Cacheable[] cacheable() default {};
|
||||
|
||||
CachePut[] put() default {};
|
||||
|
||||
CacheEvict[] evict() default {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,66 +1,66 @@
|
|||
/*
|
||||
* 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a cache invalidate operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CacheEvict {
|
||||
|
||||
/**
|
||||
* Qualifier value for the specified cached operation.
|
||||
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
||||
* value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Whether or not all the entries inside the cache(s) are removed or not. By
|
||||
* default, only the value under the associated key is removed.
|
||||
* <p>Note that specifying setting this parameter to true and specifying a
|
||||
* {@link CacheKey key} is not allowed.
|
||||
*/
|
||||
boolean allEntries() default false;
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a cache invalidate operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CacheEvict {
|
||||
|
||||
/**
|
||||
* Qualifier value for the specified cached operation.
|
||||
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
||||
* value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Whether or not all the entries inside the cache(s) are removed or not. By
|
||||
* default, only the value under the associated key is removed.
|
||||
* <p>Note that specifying setting this parameter to true and specifying a
|
||||
* {@link CacheKey key} is not allowed.
|
||||
*/
|
||||
boolean allEntries() default false;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +1,61 @@
|
|||
/*
|
||||
* Copyright 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
*
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation,
|
||||
* this annotation does not cause the target method to be skipped - rather it
|
||||
* always causes the method to be invoked and its result to be placed into the cache.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the cache update.
|
||||
* <p>Default is "", meaning the method result is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
}
|
||||
/*
|
||||
* Copyright 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation,
|
||||
* this annotation does not cause the target method to be skipped - rather it
|
||||
* always causes the method to be invoked and its result to be placed into the cache.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the cache update.
|
||||
* <p>Default is "", meaning the method result is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +1,59 @@
|
|||
/*
|
||||
* 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all the methods on a class) can be cached.
|
||||
*
|
||||
* <p>The method arguments and signature are used for computing the key while the
|
||||
* returned instance is used as the cache value.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
}
|
||||
/*
|
||||
* 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.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all the methods on a class) can be cached.
|
||||
*
|
||||
* <p>The method arguments and signature are used for computing the key while the
|
||||
* returned instance is used as the cache value.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key.
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
*/
|
||||
String condition() default "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,126 +1,127 @@
|
|||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CachePutOperation;
|
||||
import org.springframework.cache.interceptor.CacheableOperation;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing Spring's {@link Cacheable}, {@link CacheEvict} and {@link CachePut} annotations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
|
||||
|
||||
public Collection<CacheOperation> parseCacheAnnotations(AnnotatedElement ae) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
Cacheable cache = AnnotationUtils.getAnnotation(ae, Cacheable.class);
|
||||
if (cache != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseCacheableAnnotation(ae, cache));
|
||||
}
|
||||
CacheEvict evict = AnnotationUtils.getAnnotation(ae, CacheEvict.class);
|
||||
if (evict != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseEvictAnnotation(ae, evict));
|
||||
}
|
||||
CachePut update = AnnotationUtils.getAnnotation(ae, CachePut.class);
|
||||
if (update != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseUpdateAnnotation(ae, update));
|
||||
}
|
||||
CacheDefinitions definition = AnnotationUtils.getAnnotation(ae, CacheDefinitions.class);
|
||||
if (definition != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.addAll(parseDefinitionAnnotation(ae, definition));
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
private Collection<CacheOperation> lazyInit(Collection<CacheOperation> ops) {
|
||||
return (ops != null ? ops : new ArrayList<CacheOperation>(2));
|
||||
}
|
||||
|
||||
CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, Cacheable ann) {
|
||||
CacheableOperation cuo = new CacheableOperation();
|
||||
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;
|
||||
}
|
||||
|
||||
CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CachePut ann) {
|
||||
CachePutOperation cuo = new CachePutOperation();
|
||||
cuo.setCacheNames(ann.value());
|
||||
cuo.setCondition(ann.condition());
|
||||
cuo.setKey(ann.key());
|
||||
cuo.setName(ae.toString());
|
||||
return cuo;
|
||||
}
|
||||
|
||||
Collection<CacheOperation> parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinitions ann) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
Cacheable[] cacheables = ann.cacheable();
|
||||
if (!ObjectUtils.isEmpty(cacheables)) {
|
||||
ops = lazyInit(ops);
|
||||
for (Cacheable cacheable : cacheables) {
|
||||
ops.add(parseCacheableAnnotation(ae, cacheable));
|
||||
}
|
||||
}
|
||||
CacheEvict[] evicts = ann.evict();
|
||||
if (!ObjectUtils.isEmpty(evicts)) {
|
||||
ops = lazyInit(ops);
|
||||
for (CacheEvict evict : evicts) {
|
||||
ops.add(parseEvictAnnotation(ae, evict));
|
||||
}
|
||||
}
|
||||
CachePut[] updates = ann.put();
|
||||
if (!ObjectUtils.isEmpty(updates)) {
|
||||
ops = lazyInit(ops);
|
||||
for (CachePut update : updates) {
|
||||
ops.add(parseUpdateAnnotation(ae, update));
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CachePutOperation;
|
||||
import org.springframework.cache.interceptor.CacheableOperation;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing Spring's {@link Cacheable},
|
||||
* {@link CacheEvict} and {@link CachePut} annotations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
|
||||
|
||||
public Collection<CacheOperation> parseCacheAnnotations(AnnotatedElement ae) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
Cacheable cache = AnnotationUtils.getAnnotation(ae, Cacheable.class);
|
||||
if (cache != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseCacheableAnnotation(ae, cache));
|
||||
}
|
||||
CacheEvict evict = AnnotationUtils.getAnnotation(ae, CacheEvict.class);
|
||||
if (evict != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseEvictAnnotation(ae, evict));
|
||||
}
|
||||
CachePut update = AnnotationUtils.getAnnotation(ae, CachePut.class);
|
||||
if (update != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.add(parseUpdateAnnotation(ae, update));
|
||||
}
|
||||
CacheDefinitions definition = AnnotationUtils.getAnnotation(ae, CacheDefinitions.class);
|
||||
if (definition != null) {
|
||||
ops = lazyInit(ops);
|
||||
ops.addAll(parseDefinitionAnnotation(ae, definition));
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
private Collection<CacheOperation> lazyInit(Collection<CacheOperation> ops) {
|
||||
return (ops != null ? ops : new ArrayList<CacheOperation>(2));
|
||||
}
|
||||
|
||||
CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, Cacheable ann) {
|
||||
CacheableOperation cuo = new CacheableOperation();
|
||||
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;
|
||||
}
|
||||
|
||||
CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CachePut ann) {
|
||||
CachePutOperation cuo = new CachePutOperation();
|
||||
cuo.setCacheNames(ann.value());
|
||||
cuo.setCondition(ann.condition());
|
||||
cuo.setKey(ann.key());
|
||||
cuo.setName(ae.toString());
|
||||
return cuo;
|
||||
}
|
||||
|
||||
Collection<CacheOperation> parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinitions ann) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
Cacheable[] cacheables = ann.cacheable();
|
||||
if (!ObjectUtils.isEmpty(cacheables)) {
|
||||
ops = lazyInit(ops);
|
||||
for (Cacheable cacheable : cacheables) {
|
||||
ops.add(parseCacheableAnnotation(ae, cacheable));
|
||||
}
|
||||
}
|
||||
CacheEvict[] evicts = ann.evict();
|
||||
if (!ObjectUtils.isEmpty(evicts)) {
|
||||
ops = lazyInit(ops);
|
||||
for (CacheEvict evict : evicts) {
|
||||
ops.add(parseEvictAnnotation(ae, evict));
|
||||
}
|
||||
}
|
||||
CachePut[] updates = ann.put();
|
||||
if (!ObjectUtils.isEmpty(updates)) {
|
||||
ops = lazyInit(ops);
|
||||
for (CachePut update : updates) {
|
||||
ops.add(parseUpdateAnnotation(ae, update));
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
|
||||
/**
|
||||
* JDK 1.5+ annotation for caching demarcation.
|
||||
* Hooked into Spring's caching interception infrastructure
|
||||
* via CacheOperationSource implementation.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cache.annotation;
|
||||
|
||||
|
||||
/**
|
||||
* Annotations and supporting classes for declarative cache management.
|
||||
* Hooked into Spring's caching interception infrastructure
|
||||
* via {@link org.springframework.cache.interceptor.CacheOperationSource
|
||||
* CacheOperationSource} implementation.
|
||||
*/
|
||||
package org.springframework.cache.annotation;
|
||||
|
|
|
|||
|
|
@ -1,145 +1,145 @@
|
|||
/*
|
||||
* 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.io.Serializable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
|
||||
/**
|
||||
* Simple {@link Cache} implementation based on the core JDK
|
||||
* <code>java.util.concurrent</code> package.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
* dynamically through {@link ConcurrentMapCacheManager}.
|
||||
*
|
||||
* <p><b>Note:</b> As {@link ConcurrentHashMap} (the default implementation used)
|
||||
* does not allow for <code>null</code> values to be stored, this class will replace
|
||||
* them with a predefined internal object. This behavior can be changed through the
|
||||
* {@link #ConcurrentMapCache(String, ConcurrentMap, boolean)} constructor.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCache implements Cache {
|
||||
|
||||
private static final Object NULL_HOLDER = new NullHolder();
|
||||
|
||||
private final String name;
|
||||
|
||||
private final ConcurrentMap<Object, Object> store;
|
||||
|
||||
private final boolean allowNullValues;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name) {
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name, boolean allowNullValues) {
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), allowNullValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name and the
|
||||
* given internal ConcurrentMap to use.
|
||||
* @param name the name of the cache
|
||||
* @param store the ConcurrentMap to use as an internal store
|
||||
* @param allowNullValues whether to allow <code>null</code> values
|
||||
* (adapting them to an internal null holder value)
|
||||
*/
|
||||
public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {
|
||||
this.name = name;
|
||||
this.store = store;
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public ConcurrentMap getNativeCache() {
|
||||
return this.store;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Object value = this.store.get(key);
|
||||
return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
this.store.put(key, toStoreValue(value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
this.store.remove(key);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.store.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given value from the internal store to a user value
|
||||
* returned from the get method (adapting <code>null</code>).
|
||||
* @param userValue the store value
|
||||
* @return the value to return to the user
|
||||
*/
|
||||
protected Object fromStoreValue(Object storeValue) {
|
||||
if (this.allowNullValues && storeValue == NULL_HOLDER) {
|
||||
return null;
|
||||
}
|
||||
return 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 {
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.io.Serializable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
|
||||
/**
|
||||
* Simple {@link Cache} implementation based on the core JDK
|
||||
* {@code java.util.concurrent} 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} 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.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCache implements Cache {
|
||||
|
||||
private static final Object NULL_HOLDER = new NullHolder();
|
||||
|
||||
private final String name;
|
||||
|
||||
private final ConcurrentMap<Object, Object> store;
|
||||
|
||||
private final boolean allowNullValues;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name) {
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name.
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public ConcurrentMapCache(String name, boolean allowNullValues) {
|
||||
this(name, new ConcurrentHashMap<Object, Object>(), allowNullValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentMapCache with the specified name and the
|
||||
* given internal ConcurrentMap to use.
|
||||
* @param name the name of the cache
|
||||
* @param store the ConcurrentMap to use as an internal store
|
||||
* @param allowNullValues whether to allow <code>null</code> values
|
||||
* (adapting them to an internal null holder value)
|
||||
*/
|
||||
public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {
|
||||
this.name = name;
|
||||
this.store = store;
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public ConcurrentMap getNativeCache() {
|
||||
return this.store;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValues() {
|
||||
return this.allowNullValues;
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Object value = this.store.get(key);
|
||||
return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
this.store.put(key, toStoreValue(value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
this.store.remove(key);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.store.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given value from the internal store to a user value
|
||||
* returned from the get method (adapting <code>null</code>).
|
||||
* @param userValue the store value
|
||||
* @return the value to return to the user
|
||||
*/
|
||||
protected Object fromStoreValue(Object storeValue) {
|
||||
if (this.allowNullValues && storeValue == NULL_HOLDER) {
|
||||
return null;
|
||||
}
|
||||
return 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,101 +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.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} for easy configuration of a {@link ConcurrentMapCache}
|
||||
* when used within a Spring container. Can be configured through bean properties;
|
||||
* uses the assigned Spring bean name as the default cache name.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
* dynamically through {@link ConcurrentMapCacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCacheFactoryBean
|
||||
implements FactoryBean<ConcurrentMapCache>, BeanNameAware, InitializingBean {
|
||||
|
||||
private String name = "";
|
||||
|
||||
private ConcurrentMap<Object, Object> store;
|
||||
|
||||
private boolean allowNullValues = true;
|
||||
|
||||
private ConcurrentMapCache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the name of the cache.
|
||||
* <p>Default is "" (empty String).
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the ConcurrentMap to use as an internal store
|
||||
* (possibly pre-populated).
|
||||
* <p>Default is a standard {@link java.util.concurrent.ConcurrentHashMap}.
|
||||
*/
|
||||
public void setStore(ConcurrentMap<Object, Object> store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to allow <code>null</code> values
|
||||
* (adapting them to an internal null holder value).
|
||||
* <p>Default is "true".
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
if (!StringUtils.hasLength(this.name)) {
|
||||
setName(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.cache = (this.store != null ? new ConcurrentMapCache(this.name, this.store, this.allowNullValues) :
|
||||
new ConcurrentMapCache(this.name, this.allowNullValues));
|
||||
}
|
||||
|
||||
|
||||
public ConcurrentMapCache getObject() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return ConcurrentMapCache.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} for easy configuration of a {@link ConcurrentMapCache}
|
||||
* when used within a Spring container. Can be configured through bean properties;
|
||||
* uses the assigned Spring bean name as the default cache name.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
* dynamically through {@link ConcurrentMapCacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConcurrentMapCacheFactoryBean
|
||||
implements FactoryBean<ConcurrentMapCache>, BeanNameAware, InitializingBean {
|
||||
|
||||
private String name = "";
|
||||
|
||||
private ConcurrentMap<Object, Object> store;
|
||||
|
||||
private boolean allowNullValues = true;
|
||||
|
||||
private ConcurrentMapCache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the name of the cache.
|
||||
* <p>Default is "" (empty String).
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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} values
|
||||
* (adapting them to an internal null holder value).
|
||||
* <p>Default is "true".
|
||||
*/
|
||||
public void setAllowNullValues(boolean allowNullValues) {
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
if (!StringUtils.hasLength(this.name)) {
|
||||
setName(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.cache = (this.store != null ? new ConcurrentMapCache(this.name, this.store, this.allowNullValues) :
|
||||
new ConcurrentMapCache(this.name, this.allowNullValues));
|
||||
}
|
||||
|
||||
|
||||
public ConcurrentMapCache getObject() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return ConcurrentMapCache.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,101 +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);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,10 +1,9 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* Implementation package for java.util.concurrent based
|
||||
* caches. Provides a CacheManager and Cache implementation
|
||||
* for usage in a Spring context.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cache.concurrent;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation package for {@code java.util.concurrent} based caches.
|
||||
* Provides a {@link org.springframework.cache.CacheManager CacheManager}
|
||||
* and {@link org.springframework.cache.Cache Cache} implementation for
|
||||
* use in a Spring context.
|
||||
*/
|
||||
package org.springframework.cache.concurrent;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,142 +1,143 @@
|
|||
/*
|
||||
* 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.config;
|
||||
|
||||
import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
* implementation that allows users to easily configure all the infrastructure
|
||||
* beans required to enable annotation-driven cache demarcation.
|
||||
*
|
||||
* <p>By default, all proxies are created as JDK proxies. This may cause some
|
||||
* problems if you are injecting objects as concrete classes rather than
|
||||
* interfaces. To overcome this restriction you can set the
|
||||
* '<code>proxy-target-class</code>' attribute to '<code>true</code>', which
|
||||
* will result in class-based proxies being created.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Parses the '<code><cache:annotation-driven/></code>' tag. Will
|
||||
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
|
||||
* with the container as necessary.
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String mode = element.getAttribute("mode");
|
||||
if ("aspectj".equals(mode)) {
|
||||
// mode="aspectj"
|
||||
registerCacheAspect(element, parserContext);
|
||||
}
|
||||
else {
|
||||
// mode="proxy"
|
||||
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void parseCacheManagerProperty(Element element, BeanDefinition def) {
|
||||
def.getPropertyValues().add("cacheManager",
|
||||
new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a
|
||||
* <pre>
|
||||
* <bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
|
||||
* <property name="cacheManagerBeanName" value="cacheManager"/>
|
||||
* </bean>
|
||||
*
|
||||
* </pre>
|
||||
* @param element
|
||||
* @param parserContext
|
||||
*/
|
||||
private void registerCacheAspect(Element element, ParserContext parserContext) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ASPECT_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
def.setBeanClassName(CACHE_ASPECT_CLASS_NAME);
|
||||
def.setFactoryMethodName("aspectOf");
|
||||
parseCacheManagerProperty(element, def);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(def, CACHE_ASPECT_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
|
||||
*/
|
||||
private static class AopAutoProxyConfigurer {
|
||||
|
||||
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) {
|
||||
Object eleSource = parserContext.extractSource(element);
|
||||
|
||||
// Create the CacheOperationSource definition.
|
||||
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class);
|
||||
sourceDef.setSource(eleSource);
|
||||
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
|
||||
|
||||
// Create the CacheInterceptor definition.
|
||||
RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class);
|
||||
interceptorDef.setSource(eleSource);
|
||||
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parseCacheManagerProperty(element, interceptorDef);
|
||||
CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef);
|
||||
interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName));
|
||||
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||
|
||||
// Create the CacheAdvisor definition.
|
||||
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
|
||||
advisorDef.setSource(eleSource);
|
||||
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
||||
if (element.hasAttribute("order")) {
|
||||
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(CACHE_ADVISOR_BEAN_NAME, advisorDef);
|
||||
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
|
||||
eleSource);
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CACHE_ADVISOR_BEAN_NAME));
|
||||
parserContext.registerComponent(compositeDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
* implementation that allows users to easily configure all the
|
||||
* infrastructure beans required to enable annotation-driven cache
|
||||
* demarcation.
|
||||
*
|
||||
* <p>By default, all proxies are created as JDK proxies. This may cause
|
||||
* some problems if you are injecting objects as concrete classes rather
|
||||
* than interfaces. To overcome this restriction you can set the
|
||||
* '{@code proxy-target-class}' attribute to '{@code true}', which will
|
||||
* result in class-based proxies being created.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Parses the '{@code <cache:annotation-driven>}' tag. Will
|
||||
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary
|
||||
* register an AutoProxyCreator} with the container as necessary.
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String mode = element.getAttribute("mode");
|
||||
if ("aspectj".equals(mode)) {
|
||||
// mode="aspectj"
|
||||
registerCacheAspect(element, parserContext);
|
||||
}
|
||||
else {
|
||||
// mode="proxy"
|
||||
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void parseCacheManagerProperty(Element element, BeanDefinition def) {
|
||||
def.getPropertyValues().add("cacheManager",
|
||||
new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a
|
||||
* <pre>
|
||||
* <bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
|
||||
* <property name="cacheManagerBeanName" value="cacheManager"/>
|
||||
* </bean>
|
||||
*
|
||||
* </pre>
|
||||
* @param element
|
||||
* @param parserContext
|
||||
*/
|
||||
private void registerCacheAspect(Element element, ParserContext parserContext) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ASPECT_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
def.setBeanClassName(CACHE_ASPECT_CLASS_NAME);
|
||||
def.setFactoryMethodName("aspectOf");
|
||||
parseCacheManagerProperty(element, def);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(def, CACHE_ASPECT_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
|
||||
*/
|
||||
private static class AopAutoProxyConfigurer {
|
||||
|
||||
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) {
|
||||
Object eleSource = parserContext.extractSource(element);
|
||||
|
||||
// Create the CacheOperationSource definition.
|
||||
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class);
|
||||
sourceDef.setSource(eleSource);
|
||||
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
|
||||
|
||||
// Create the CacheInterceptor definition.
|
||||
RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class);
|
||||
interceptorDef.setSource(eleSource);
|
||||
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parseCacheManagerProperty(element, interceptorDef);
|
||||
CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef);
|
||||
interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName));
|
||||
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||
|
||||
// Create the CacheAdvisor definition.
|
||||
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
|
||||
advisorDef.setSource(eleSource);
|
||||
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
||||
if (element.hasAttribute("order")) {
|
||||
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(CACHE_ADVISOR_BEAN_NAME, advisorDef);
|
||||
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
|
||||
eleSource);
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CACHE_ADVISOR_BEAN_NAME));
|
||||
parserContext.registerComponent(compositeDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,216 +1,215 @@
|
|||
/*
|
||||
* Copyright 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CachePutOperation;
|
||||
import org.springframework.cache.interceptor.CacheableOperation;
|
||||
import org.springframework.cache.interceptor.NameMatchCacheOperationSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||
* BeanDefinitionParser} for the {@code <tx:advice/>} tag.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*
|
||||
*/
|
||||
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Simple, reusable class used for overriding defaults.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
private static class Props {
|
||||
|
||||
private String key, condition, method;
|
||||
private String[] caches = null;
|
||||
|
||||
Props(Element root) {
|
||||
String defaultCache = root.getAttribute("cache");
|
||||
key = root.getAttribute("key");
|
||||
condition = root.getAttribute("condition");
|
||||
method = root.getAttribute(METHOD_ATTRIBUTE);
|
||||
|
||||
if (StringUtils.hasText(defaultCache)) {
|
||||
caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim());
|
||||
}
|
||||
}
|
||||
|
||||
CacheOperation merge(Element element, ReaderContext readerCtx, CacheOperation op) {
|
||||
String cache = element.getAttribute("cache");
|
||||
String k = element.getAttribute("key");
|
||||
String c = element.getAttribute("condition");
|
||||
|
||||
String[] localCaches = caches;
|
||||
String localKey = key, localCondition = condition;
|
||||
|
||||
// sanity check
|
||||
if (StringUtils.hasText(cache)) {
|
||||
localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim());
|
||||
} else {
|
||||
if (caches == null) {
|
||||
readerCtx.error("No cache specified specified for " + element.getNodeName(), element);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(k)) {
|
||||
localKey = k.trim();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(c)) {
|
||||
localCondition = c.trim();
|
||||
}
|
||||
op.setCacheNames(localCaches);
|
||||
op.setKey(localKey);
|
||||
op.setCondition(localCondition);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
String merge(Element element, ReaderContext readerCtx) {
|
||||
String m = element.getAttribute(METHOD_ATTRIBUTE);
|
||||
|
||||
if (StringUtils.hasText(m)) {
|
||||
return m.trim();
|
||||
}
|
||||
if (StringUtils.hasText(method)) {
|
||||
return method;
|
||||
}
|
||||
readerCtx.error("No method specified for " + element.getNodeName(), element);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String CACHEABLE_ELEMENT = "cacheable";
|
||||
private static final String CACHE_EVICT_ELEMENT = "cache-evict";
|
||||
private static final String CACHE_PUT_ELEMENT = "cache-put";
|
||||
private static final String METHOD_ATTRIBUTE = "method";
|
||||
private static final String DEFS_ELEMENT = "definitions";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CacheInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
|
||||
CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition());
|
||||
|
||||
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
|
||||
if (cacheDefs.size() >= 1) {
|
||||
// Using attributes source.
|
||||
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
|
||||
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
|
||||
} else {
|
||||
// Assume annotations source.
|
||||
builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition(
|
||||
AnnotationCacheOperationSource.class));
|
||||
}
|
||||
}
|
||||
|
||||
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
|
||||
ManagedList<RootBeanDefinition> defs = new ManagedList<RootBeanDefinition>(definitions.size());
|
||||
|
||||
// extract default param for the definition
|
||||
for (Element element : definitions) {
|
||||
defs.add(parseDefinitionSource(element, parserContext));
|
||||
}
|
||||
|
||||
return defs;
|
||||
}
|
||||
|
||||
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
|
||||
Props prop = new Props(definition);
|
||||
// add cacheable first
|
||||
|
||||
ManagedMap<TypedStringValue, Collection<CacheOperation>> cacheOpMap = new ManagedMap<TypedStringValue, Collection<CacheOperation>>();
|
||||
cacheOpMap.setSource(parserContext.extractSource(definition));
|
||||
|
||||
List<Element> cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
|
||||
|
||||
for (Element opElement : cacheableCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
List<Element> evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT);
|
||||
|
||||
for (Element opElement : evictCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
List<Element> putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT);
|
||||
|
||||
for (Element opElement : putCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class);
|
||||
attributeSourceDefinition.setSource(parserContext.extractSource(definition));
|
||||
attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap);
|
||||
return attributeSourceDefinition;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CachePutOperation;
|
||||
import org.springframework.cache.interceptor.CacheableOperation;
|
||||
import org.springframework.cache.interceptor.NameMatchCacheOperationSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||
* BeanDefinitionParser} for the {@code <tx:advice/>} tag.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Simple, reusable class used for overriding defaults.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
private static class Props {
|
||||
|
||||
private String key, condition, method;
|
||||
private String[] caches = null;
|
||||
|
||||
Props(Element root) {
|
||||
String defaultCache = root.getAttribute("cache");
|
||||
key = root.getAttribute("key");
|
||||
condition = root.getAttribute("condition");
|
||||
method = root.getAttribute(METHOD_ATTRIBUTE);
|
||||
|
||||
if (StringUtils.hasText(defaultCache)) {
|
||||
caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim());
|
||||
}
|
||||
}
|
||||
|
||||
CacheOperation merge(Element element, ReaderContext readerCtx, CacheOperation op) {
|
||||
String cache = element.getAttribute("cache");
|
||||
String k = element.getAttribute("key");
|
||||
String c = element.getAttribute("condition");
|
||||
|
||||
String[] localCaches = caches;
|
||||
String localKey = key, localCondition = condition;
|
||||
|
||||
// sanity check
|
||||
if (StringUtils.hasText(cache)) {
|
||||
localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim());
|
||||
} else {
|
||||
if (caches == null) {
|
||||
readerCtx.error("No cache specified specified for " + element.getNodeName(), element);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(k)) {
|
||||
localKey = k.trim();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(c)) {
|
||||
localCondition = c.trim();
|
||||
}
|
||||
op.setCacheNames(localCaches);
|
||||
op.setKey(localKey);
|
||||
op.setCondition(localCondition);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
String merge(Element element, ReaderContext readerCtx) {
|
||||
String m = element.getAttribute(METHOD_ATTRIBUTE);
|
||||
|
||||
if (StringUtils.hasText(m)) {
|
||||
return m.trim();
|
||||
}
|
||||
if (StringUtils.hasText(method)) {
|
||||
return method;
|
||||
}
|
||||
readerCtx.error("No method specified for " + element.getNodeName(), element);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String CACHEABLE_ELEMENT = "cacheable";
|
||||
private static final String CACHE_EVICT_ELEMENT = "cache-evict";
|
||||
private static final String CACHE_PUT_ELEMENT = "cache-put";
|
||||
private static final String METHOD_ATTRIBUTE = "method";
|
||||
private static final String DEFS_ELEMENT = "definitions";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CacheInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
|
||||
CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition());
|
||||
|
||||
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
|
||||
if (cacheDefs.size() >= 1) {
|
||||
// Using attributes source.
|
||||
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
|
||||
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
|
||||
} else {
|
||||
// Assume annotations source.
|
||||
builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition(
|
||||
AnnotationCacheOperationSource.class));
|
||||
}
|
||||
}
|
||||
|
||||
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
|
||||
ManagedList<RootBeanDefinition> defs = new ManagedList<RootBeanDefinition>(definitions.size());
|
||||
|
||||
// extract default param for the definition
|
||||
for (Element element : definitions) {
|
||||
defs.add(parseDefinitionSource(element, parserContext));
|
||||
}
|
||||
|
||||
return defs;
|
||||
}
|
||||
|
||||
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
|
||||
Props prop = new Props(definition);
|
||||
// add cacheable first
|
||||
|
||||
ManagedMap<TypedStringValue, Collection<CacheOperation>> cacheOpMap = new ManagedMap<TypedStringValue, Collection<CacheOperation>>();
|
||||
cacheOpMap.setSource(parserContext.extractSource(definition));
|
||||
|
||||
List<Element> cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
|
||||
|
||||
for (Element opElement : cacheableCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
List<Element> evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT);
|
||||
|
||||
for (Element opElement : evictCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
List<Element> putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT);
|
||||
|
||||
for (Element opElement : putCacheMethods) {
|
||||
String name = prop.merge(opElement, parserContext.getReaderContext());
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation());
|
||||
|
||||
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
|
||||
if (col == null) {
|
||||
col = new ArrayList<CacheOperation>(2);
|
||||
cacheOpMap.put(nameHolder, col);
|
||||
}
|
||||
col.add(op);
|
||||
}
|
||||
|
||||
RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class);
|
||||
attributeSourceDefinition.setSource(parserContext.extractSource(definition));
|
||||
attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap);
|
||||
return attributeSourceDefinition;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,58 @@
|
|||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* <code>NamespaceHandler</code> allowing for the configuration of
|
||||
* declarative cache management using either XML or using annotations.
|
||||
*
|
||||
* <p>This namespace handler is the central piece of functionality in the
|
||||
* Spring cache management facilities.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager";
|
||||
static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
|
||||
|
||||
static String extractCacheManager(Element element) {
|
||||
return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element
|
||||
.getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE)
|
||||
: CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
}
|
||||
|
||||
static BeanDefinition parseKeyGenerator(Element element, BeanDefinition def) {
|
||||
String name = element.getAttribute("key-generator");
|
||||
if (StringUtils.hasText(name)) {
|
||||
def.getPropertyValues().add("keyGenerator", new RuntimeBeanReference(name.trim()));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("advice", new CacheAdviceParser());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@code NamespaceHandler} allowing for the configuration of declarative
|
||||
* cache management using either XML or using annotations.
|
||||
*
|
||||
* <p>This namespace handler is the central piece of functionality in the
|
||||
* Spring cache management facilities.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager";
|
||||
static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
|
||||
|
||||
static String extractCacheManager(Element element) {
|
||||
return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element
|
||||
.getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE)
|
||||
: CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
}
|
||||
|
||||
static BeanDefinition parseKeyGenerator(Element element, BeanDefinition def) {
|
||||
String name = element.getAttribute("key-generator");
|
||||
if (StringUtils.hasText(name)) {
|
||||
def.getPropertyValues().add("keyGenerator", new RuntimeBeanReference(name.trim()));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("advice", new CacheAdviceParser());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* Support package for declarative caching configuration,
|
||||
* with XML schema being the primary configuration format.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cache.config;
|
||||
|
||||
|
||||
/**
|
||||
* Support package for declarative caching configuration, with XML
|
||||
* schema being the primary configuration format. See {@link
|
||||
* org.springframework.cache.annotation.EnableCaching EnableCaching}
|
||||
* for details on code-based configuration without XML.
|
||||
*/
|
||||
package org.springframework.cache.config;
|
||||
|
|
|
|||
|
|
@ -1,77 +1,77 @@
|
|||
/*
|
||||
* 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.ehcache;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCache implements Cache {
|
||||
|
||||
private final Ehcache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Create an {@link EhCacheCache} instance.
|
||||
* @param ehcache backing Ehcache instance
|
||||
*/
|
||||
public EhCacheCache(Ehcache ehcache) {
|
||||
Assert.notNull(ehcache, "Ehcache must not be null");
|
||||
Status status = ehcache.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' Ehcache is required - current cache is " + status.toString());
|
||||
this.cache = ehcache;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
public Ehcache getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.cache.removeAll();
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Element element = this.cache.get(key);
|
||||
return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
this.cache.put(new Element(key, value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
this.cache.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.ehcache;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.ValueWrapperImpl;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCache implements Cache {
|
||||
|
||||
private final Ehcache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Create an {@link EhCacheCache} instance.
|
||||
* @param ehcache backing Ehcache instance
|
||||
*/
|
||||
public EhCacheCache(Ehcache ehcache) {
|
||||
Assert.notNull(ehcache, "Ehcache must not be null");
|
||||
Status status = ehcache.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' Ehcache is required - current cache is " + status.toString());
|
||||
this.cache = ehcache;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
public Ehcache getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.cache.removeAll();
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
Element element = this.cache.get(key);
|
||||
return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
this.cache.put(new Element(key, value));
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
this.cache.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,79 +1,79 @@
|
|||
/*
|
||||
* 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.ehcache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.AbstractCacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCacheManager extends AbstractCacheManager {
|
||||
|
||||
private net.sf.ehcache.CacheManager cacheManager;
|
||||
|
||||
|
||||
/**
|
||||
* Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*/
|
||||
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required");
|
||||
Status status = this.cacheManager.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
|
||||
String[] names = this.cacheManager.getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(this.cacheManager.getEhcache(name)));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the EhCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
Ehcache ehcache = this.cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
cache = new EhCacheCache(ehcache);
|
||||
addCache(cache);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.ehcache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.AbstractCacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class EhCacheCacheManager extends AbstractCacheManager {
|
||||
|
||||
private net.sf.ehcache.CacheManager cacheManager;
|
||||
|
||||
|
||||
/**
|
||||
* Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*/
|
||||
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required");
|
||||
Status status = this.cacheManager.getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
|
||||
String[] names = this.cacheManager.getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(this.cacheManager.getEhcache(name)));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = super.getCache(name);
|
||||
if (cache == null) {
|
||||
// check the EhCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
Ehcache ehcache = this.cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
cache = new EhCacheCache(ehcache);
|
||||
addCache(cache);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,218 +1,221 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link CacheOperation} that caches
|
||||
* attributes for methods and implements a fallback policy: 1. specific target
|
||||
* method; 2. target class; 3. declaring method; 4. declaring class/interface.
|
||||
*
|
||||
* <p>Defaults to using the target class's caching attribute if none is
|
||||
* associated with the target method. Any caching attribute associated with
|
||||
* the target method completely overrides a class caching attribute.
|
||||
* If none found on the target class, the interface that the invoked method
|
||||
* has been called through (in case of a JDK proxy) will be checked.
|
||||
*
|
||||
* <p>This implementation caches attributes by method after they are first used.
|
||||
* If it is ever desirable to allow dynamic changing of cacheable attributes
|
||||
* (which is very unlikely), caching could be made configurable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
|
||||
|
||||
/**
|
||||
* Canonical value held in cache to indicate no caching attribute was
|
||||
* found for this method and we don't need to look again.
|
||||
*/
|
||||
private final static Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>As this base class is not marked Serializable, the logger will be recreated
|
||||
* after serialization - provided that the concrete subclass is Serializable.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Cache of CacheOperationDefinitions, keyed by DefaultCacheKey (Method + target Class).
|
||||
* <p>As this base class is not marked Serializable, the cache will be recreated
|
||||
* after serialization - provided that the concrete subclass is Serializable.
|
||||
*/
|
||||
final Map<Object, Collection<CacheOperation>> attributeCache = new ConcurrentHashMap<Object, Collection<CacheOperation>>();
|
||||
|
||||
|
||||
/**
|
||||
* Determine the caching attribute for this method invocation.
|
||||
* <p>Defaults to the class's caching attribute if no method attribute is found.
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||
* @return {@link CacheOperation} for this method, or <code>null</code> if the method
|
||||
* is not cacheable
|
||||
*/
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = getCacheKey(method, targetClass);
|
||||
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
if (cached == NULL_CACHING_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
// Value will either be canonical value indicating there is no caching attribute,
|
||||
// or an actual caching attribute.
|
||||
return cached;
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
Collection<CacheOperation> cacheDefs = computeCacheOperationDefinition(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cacheDefs == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheDefs);
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cacheDefs);
|
||||
}
|
||||
return cacheDefs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a cache key for the given method and target class.
|
||||
* <p>Must not produce same key for overloaded methods.
|
||||
* Must produce same key for different instances of the same method.
|
||||
* @param method the method (never <code>null</code>)
|
||||
* @param targetClass the target class (may be <code>null</code>)
|
||||
* @return the cache key (never <code>null</code>)
|
||||
*/
|
||||
protected Object getCacheKey(Method method, Class<?> targetClass) {
|
||||
return new DefaultCacheKey(method, targetClass);
|
||||
}
|
||||
|
||||
private Collection<CacheOperation> computeCacheOperationDefinition(Method method, Class<?> targetClass) {
|
||||
// Don't allow no-public methods as required.
|
||||
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// If we are dealing with method with generic parameters, find the original method.
|
||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
|
||||
// First try is the method in the target class.
|
||||
Collection<CacheOperation> opDef = findCacheOperations(specificMethod);
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
|
||||
// Second try is the caching operation on the target class.
|
||||
opDef = findCacheOperations(specificMethod.getDeclaringClass());
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
|
||||
if (specificMethod != method) {
|
||||
// Fall back is to look at the original method.
|
||||
opDef = findCacheOperations(method);
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
// Last fall back is the class of the original method.
|
||||
return findCacheOperations(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching attribute
|
||||
* for the given method, if any.
|
||||
* @param method the method to retrieve the attribute for
|
||||
* @return all caching attribute associated with this method
|
||||
* (or <code>null</code> if none)
|
||||
*/
|
||||
protected abstract Collection<CacheOperation> findCacheOperations(Method method);
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching attribute
|
||||
* for the given class, if any.
|
||||
* @param clazz the class to retrieve the attribute for
|
||||
* @return all caching attribute associated with this class
|
||||
* (or <code>null</code> if none)
|
||||
*/
|
||||
protected abstract Collection<CacheOperation> findCacheOperations(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Should only public methods be allowed to have caching semantics?
|
||||
* <p>The default implementation returns <code>false</code>.
|
||||
*/
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default cache key for the CacheOperation cache.
|
||||
*/
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
public DefaultCacheKey(Method method, Class<?> targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass,
|
||||
otherKey.targetClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link CacheOperation} that caches
|
||||
* attributes for methods and implements a fallback policy: 1. specific
|
||||
* target method; 2. target class; 3. declaring method; 4. declaring
|
||||
* class/interface.
|
||||
*
|
||||
* <p>Defaults to using the target class's caching attribute if none is
|
||||
* associated with the target method. Any caching attribute associated
|
||||
* with the target method completely overrides a class caching attribute.
|
||||
* If none found on the target class, the interface that the invoked
|
||||
* method has been called through (in case of a JDK proxy) will be
|
||||
* checked.
|
||||
*
|
||||
* <p>This implementation caches attributes by method after they are
|
||||
* first used. If it is ever desirable to allow dynamic changing of
|
||||
* cacheable attributes (which is very unlikely), caching could be made
|
||||
* configurable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
|
||||
|
||||
/**
|
||||
* Canonical value held in cache to indicate no caching attribute was
|
||||
* found for this method and we don't need to look again.
|
||||
*/
|
||||
private final static Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>As this base class is not marked Serializable, the logger will be recreated
|
||||
* after serialization - provided that the concrete subclass is Serializable.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Cache of CacheOperationDefinitions, keyed by DefaultCacheKey (Method + target Class).
|
||||
* <p>As this base class is not marked Serializable, the cache will be recreated
|
||||
* after serialization - provided that the concrete subclass is Serializable.
|
||||
*/
|
||||
final Map<Object, Collection<CacheOperation>> attributeCache = new ConcurrentHashMap<Object, Collection<CacheOperation>>();
|
||||
|
||||
|
||||
/**
|
||||
* Determine the caching attribute for this method invocation.
|
||||
* <p>Defaults to the class's caching attribute if no method attribute is found.
|
||||
* @param method the method for the current invocation (never {@code null})
|
||||
* @param targetClass the target class for this invocation (may be {@code null})
|
||||
* @return {@link CacheOperation} for this method, or {@code null} if the method
|
||||
* is not cacheable
|
||||
*/
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = getCacheKey(method, targetClass);
|
||||
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
if (cached == NULL_CACHING_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
// Value will either be canonical value indicating there is no caching attribute,
|
||||
// or an actual caching attribute.
|
||||
return cached;
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
Collection<CacheOperation> cacheDefs = computeCacheOperationDefinition(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cacheDefs == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheDefs);
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cacheDefs);
|
||||
}
|
||||
return cacheDefs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a cache key for the given method and target class.
|
||||
* <p>Must not produce same key for overloaded methods.
|
||||
* Must produce same key for different instances of the same method.
|
||||
* @param method the method (never {@code null})
|
||||
* @param targetClass the target class (may be {@code null})
|
||||
* @return the cache key (never {@code null})
|
||||
*/
|
||||
protected Object getCacheKey(Method method, Class<?> targetClass) {
|
||||
return new DefaultCacheKey(method, targetClass);
|
||||
}
|
||||
|
||||
private Collection<CacheOperation> computeCacheOperationDefinition(Method method, Class<?> targetClass) {
|
||||
// Don't allow no-public methods as required.
|
||||
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// If we are dealing with method with generic parameters, find the original method.
|
||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
|
||||
// First try is the method in the target class.
|
||||
Collection<CacheOperation> opDef = findCacheOperations(specificMethod);
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
|
||||
// Second try is the caching operation on the target class.
|
||||
opDef = findCacheOperations(specificMethod.getDeclaringClass());
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
|
||||
if (specificMethod != method) {
|
||||
// Fall back is to look at the original method.
|
||||
opDef = findCacheOperations(method);
|
||||
if (opDef != null) {
|
||||
return opDef;
|
||||
}
|
||||
// Last fall back is the class of the original method.
|
||||
return findCacheOperations(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching attribute
|
||||
* for the given method, if any.
|
||||
* @param method the method to retrieve the attribute for
|
||||
* @return all caching attribute associated with this method
|
||||
* (or {@code null} if none)
|
||||
*/
|
||||
protected abstract Collection<CacheOperation> findCacheOperations(Method method);
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching attribute
|
||||
* for the given class, if any.
|
||||
* @param clazz the class to retrieve the attribute for
|
||||
* @return all caching attribute associated with this class
|
||||
* (or {@code null} if none)
|
||||
*/
|
||||
protected abstract Collection<CacheOperation> findCacheOperations(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Should only public methods be allowed to have caching semantics?
|
||||
* <p>The default implementation returns {@code false}.
|
||||
*/
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default cache key for the CacheOperation cache.
|
||||
*/
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
public DefaultCacheKey(Method method, Class<?> targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass,
|
||||
otherKey.targetClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +1,65 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Advisor driven by a {@link CacheOperationSource}, used to include a
|
||||
* cache advice bean for methods that are cacheable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
|
||||
@Override
|
||||
protected CacheOperationSource getCacheOperationSource() {
|
||||
return cacheOperationSource;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the cache operation attribute source which is used to find cache
|
||||
* attributes. This should usually be identical to the source reference
|
||||
* set on the cache interceptor itself.
|
||||
* @see CacheInterceptor#setCacheAttributeSource
|
||||
*/
|
||||
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ClassFilter} to use for this pointcut.
|
||||
* Default is {@link ClassFilter#TRUE}.
|
||||
*/
|
||||
public void setClassFilter(ClassFilter classFilter) {
|
||||
this.pointcut.setClassFilter(classFilter);
|
||||
}
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Advisor driven by a {@link CacheOperationSource}, used to include a
|
||||
* cache advice bean for methods that are cacheable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
|
||||
@Override
|
||||
protected CacheOperationSource getCacheOperationSource() {
|
||||
return cacheOperationSource;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the cache operation attribute source which is used to find cache
|
||||
* attributes. This should usually be identical to the source reference
|
||||
* set on the cache interceptor itself.
|
||||
* @see CacheInterceptor#setCacheAttributeSource
|
||||
*/
|
||||
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ClassFilter} to use for this pointcut.
|
||||
* Default is {@link ClassFilter#TRUE}.
|
||||
*/
|
||||
public void setClassFilter(ClassFilter classFilter) {
|
||||
this.pointcut.setClassFilter(classFilter);
|
||||
}
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,463 +1,465 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for caching aspects, such as the {@link CacheInterceptor}
|
||||
* or an AspectJ aspect.
|
||||
*
|
||||
* <p>This enables the underlying Spring caching infrastructure to be used easily
|
||||
* to implement an aspect for any aspect system.
|
||||
*
|
||||
* <p>Subclasses are responsible for calling methods in this class in the correct order.
|
||||
*
|
||||
* <p>Uses the <b>Strategy</b> design pattern. A {@link CacheManager} implementation will
|
||||
* perform the actual cache management, and a {@link CacheOperationSource} is used for
|
||||
* determining caching operation definitions.
|
||||
*
|
||||
* <p>A cache aspect is serializable if its {@code CacheManager} and
|
||||
* {@code CacheOperationSource} are serializable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
public interface Invoker {
|
||||
Object invoke();
|
||||
}
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict";
|
||||
|
||||
/**
|
||||
* 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 one or more cache definition sources which are used to find the cache
|
||||
* attributes. If more than one source is provided, they will be aggregated using a
|
||||
* {@link CompositeCacheOperationSource}.
|
||||
* @param cacheOperationSources must not be {@code null}
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources);
|
||||
this.cacheOperationSource =
|
||||
(cacheOperationSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheOperationSources) :
|
||||
cacheOperationSources[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource for this cache aspect.
|
||||
*/
|
||||
public CacheOperationSource getCacheOperationSource() {
|
||||
return this.cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the KeyGenerator for this cache aspect.
|
||||
* Default is {@link DefaultKeyGenerator}.
|
||||
*/
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyGenerator for this cache aspect,
|
||||
*/
|
||||
public KeyGenerator getKeyGenerator() {
|
||||
return this.keyGenerator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.cacheManager == null) {
|
||||
throw new IllegalStateException("'cacheManager' is required");
|
||||
}
|
||||
if (this.cacheOperationSource == null) {
|
||||
throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: "
|
||||
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return a String representation of this Method
|
||||
* for use in logging. Can be overridden in subclasses to provide a
|
||||
* different identifier for the given method.
|
||||
* @param method the method we're interested in
|
||||
* @param targetClass class the method is on
|
||||
* @return log message identifying this method
|
||||
* @see org.springframework.util.ClassUtils#getQualifiedMethodName
|
||||
*/
|
||||
protected String methodIdentification(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches(CacheOperation operation) {
|
||||
Set<String> cacheNames = operation.getCacheNames();
|
||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = this.cacheManager.getCache(cacheName);
|
||||
if (cache == null) {
|
||||
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
||||
}
|
||||
caches.add(cache);
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
|
||||
return new CacheOperationContext(operation, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
protected Object execute(Invoker invoker, Object target, Method method, Object[] args) {
|
||||
// check whether aspect is enabled
|
||||
// to cope with cases where the AJ is pulled in automatically
|
||||
if (!this.initialized) {
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
// get backing class
|
||||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
||||
if (targetClass == null && target != null) {
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
|
||||
|
||||
// analyze caching information
|
||||
if (!CollectionUtils.isEmpty(cacheOp)) {
|
||||
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target,
|
||||
targetClass);
|
||||
|
||||
// start with evictions
|
||||
inspectCacheEvicts(ops.get(EVICT));
|
||||
|
||||
// follow up with cacheable
|
||||
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
|
||||
|
||||
Object retVal = null;
|
||||
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
|
||||
|
||||
if (status != null) {
|
||||
if (status.updateRequired) {
|
||||
updates.putAll(status.cUpdates);
|
||||
}
|
||||
// return cached object
|
||||
else {
|
||||
return status.retVal;
|
||||
}
|
||||
}
|
||||
|
||||
retVal = invoker.invoke();
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
update(updates, retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions) {
|
||||
|
||||
if (!evictions.isEmpty()) {
|
||||
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : evictions) {
|
||||
if (context.isConditionPassing()) {
|
||||
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
|
||||
|
||||
// for each cache
|
||||
// lazy key initialization
|
||||
Object key = null;
|
||||
|
||||
for (Cache cache : context.getCaches()) {
|
||||
// cache-wide flush
|
||||
if (evictOp.isCacheWide()) {
|
||||
cache.clear();
|
||||
if (log) {
|
||||
logger.trace("Invalidating entire cache for definition " + evictOp + " on method " + context.method);
|
||||
}
|
||||
} else {
|
||||
// check key
|
||||
if (key == null) {
|
||||
key = context.generateKey();
|
||||
}
|
||||
if (log) {
|
||||
logger.trace("Invalidating cache key " + key + " for definition " + evictOp + " on method " + context.method);
|
||||
}
|
||||
cache.evict(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(
|
||||
cacheables.size());
|
||||
|
||||
boolean updateRequire = false;
|
||||
Object retVal = null;
|
||||
|
||||
if (!cacheables.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
boolean atLeastOnePassed = false;
|
||||
|
||||
for (CacheOperationContext context : cacheables) {
|
||||
if (context.isConditionPassing()) {
|
||||
atLeastOnePassed = true;
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for definition " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
|
||||
boolean localCacheHit = false;
|
||||
|
||||
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
|
||||
if (!updateRequire) {
|
||||
for (Cache cache : context.getCaches()) {
|
||||
Cache.ValueWrapper wrapper = cache.get(key);
|
||||
if (wrapper != null) {
|
||||
retVal = wrapper.get();
|
||||
localCacheHit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!localCacheHit) {
|
||||
updateRequire = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return a status only if at least on cacheable matched
|
||||
if (atLeastOnePassed) {
|
||||
return new CacheStatus(cUpdates, updateRequire, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class CacheStatus {
|
||||
// caches/key
|
||||
final Map<CacheOperationContext, Object> cUpdates;
|
||||
final boolean updateRequired;
|
||||
final Object retVal;
|
||||
|
||||
CacheStatus(Map<CacheOperationContext, Object> cUpdates, boolean updateRequired, Object retVal) {
|
||||
this.cUpdates = cUpdates;
|
||||
this.updateRequired = updateRequired;
|
||||
this.retVal = retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<CacheOperationContext, Object> inspectCacheUpdates(Collection<CacheOperationContext> updates) {
|
||||
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : updates) {
|
||||
if (context.isConditionPassing()) {
|
||||
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for definition " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cUpdates;
|
||||
}
|
||||
|
||||
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
|
||||
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
|
||||
for (Cache cache : entry.getKey().getCaches()) {
|
||||
cache.put(entry.getValue(), retVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Collection<CacheOperationContext>> createOperationContext(Collection<CacheOperation> cacheOp,
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
Map<String, Collection<CacheOperationContext>> map = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
|
||||
|
||||
Collection<CacheOperationContext> cacheables = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> evicts = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> updates = new ArrayList<CacheOperationContext>();
|
||||
|
||||
for (CacheOperation cacheOperation : cacheOp) {
|
||||
CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass);
|
||||
|
||||
if (cacheOperation instanceof CacheableOperation) {
|
||||
cacheables.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CacheEvictOperation) {
|
||||
evicts.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CachePutOperation) {
|
||||
updates.add(opContext);
|
||||
}
|
||||
}
|
||||
|
||||
map.put(CACHEABLE, cacheables);
|
||||
map.put(EVICT, evicts);
|
||||
map.put(UPDATE, updates);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected class CacheOperationContext {
|
||||
|
||||
private final CacheOperation operation;
|
||||
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
// context passed around to avoid multiple creations
|
||||
private final EvaluationContext evalContext;
|
||||
|
||||
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target,
|
||||
Class<?> targetClass) {
|
||||
this.operation = operation;
|
||||
this.caches = CacheAspectSupport.this.getCaches(operation);
|
||||
this.target = target;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
|
||||
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
protected boolean isConditionPassing() {
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the key for the given caching operation.
|
||||
* @return generated key (null if none can be generated)
|
||||
*/
|
||||
protected Object generateKey() {
|
||||
if (StringUtils.hasText(this.operation.getKey())) {
|
||||
return evaluator.key(this.operation.getKey(), this.method, this.evalContext);
|
||||
}
|
||||
return keyGenerator.generate(this.target, this.method, this.args);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for caching aspects, such as the {@link CacheInterceptor}
|
||||
* or an AspectJ aspect.
|
||||
*
|
||||
* <p>This enables the underlying Spring caching infrastructure to be
|
||||
* used easily to implement an aspect for any aspect system.
|
||||
*
|
||||
* <p>Subclasses are responsible for calling methods in this class in
|
||||
* the correct order.
|
||||
*
|
||||
* <p>Uses the <b>Strategy</b> design pattern. A {@link CacheManager}
|
||||
* implementation will perform the actual cache management, and a
|
||||
* {@link CacheOperationSource} is used for determining caching
|
||||
* operation definitions.
|
||||
*
|
||||
* <p>A cache aspect is serializable if its {@code CacheManager} and
|
||||
* {@code CacheOperationSource} are serializable.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
public interface Invoker {
|
||||
Object invoke();
|
||||
}
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict";
|
||||
|
||||
/**
|
||||
* 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 one or more cache definition sources which are used to find the cache
|
||||
* attributes. If more than one source is provided, they will be aggregated using a
|
||||
* {@link CompositeCacheOperationSource}.
|
||||
* @param cacheOperationSources must not be {@code null}
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources);
|
||||
this.cacheOperationSource =
|
||||
(cacheOperationSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheOperationSources) :
|
||||
cacheOperationSources[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource for this cache aspect.
|
||||
*/
|
||||
public CacheOperationSource getCacheOperationSource() {
|
||||
return this.cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the KeyGenerator for this cache aspect.
|
||||
* Default is {@link DefaultKeyGenerator}.
|
||||
*/
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyGenerator for this cache aspect,
|
||||
*/
|
||||
public KeyGenerator getKeyGenerator() {
|
||||
return this.keyGenerator;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.cacheManager == null) {
|
||||
throw new IllegalStateException("'cacheManager' is required");
|
||||
}
|
||||
if (this.cacheOperationSource == null) {
|
||||
throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: "
|
||||
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return a String representation of this Method
|
||||
* for use in logging. Can be overridden in subclasses to provide a
|
||||
* different identifier for the given method.
|
||||
* @param method the method we're interested in
|
||||
* @param targetClass class the method is on
|
||||
* @return log message identifying this method
|
||||
* @see org.springframework.util.ClassUtils#getQualifiedMethodName
|
||||
*/
|
||||
protected String methodIdentification(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches(CacheOperation operation) {
|
||||
Set<String> cacheNames = operation.getCacheNames();
|
||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = this.cacheManager.getCache(cacheName);
|
||||
if (cache == null) {
|
||||
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
||||
}
|
||||
caches.add(cache);
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args,
|
||||
Object target, Class<?> targetClass) {
|
||||
|
||||
return new CacheOperationContext(operation, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
protected Object execute(Invoker invoker, Object target, Method method, Object[] args) {
|
||||
// check whether aspect is enabled
|
||||
// to cope with cases where the AJ is pulled in automatically
|
||||
if (!this.initialized) {
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
// get backing class
|
||||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
|
||||
if (targetClass == null && target != null) {
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
|
||||
|
||||
// analyze caching information
|
||||
if (!CollectionUtils.isEmpty(cacheOp)) {
|
||||
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target,
|
||||
targetClass);
|
||||
|
||||
// start with evictions
|
||||
inspectCacheEvicts(ops.get(EVICT));
|
||||
|
||||
// follow up with cacheable
|
||||
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
|
||||
|
||||
Object retVal = null;
|
||||
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
|
||||
|
||||
if (status != null) {
|
||||
if (status.updateRequired) {
|
||||
updates.putAll(status.cUpdates);
|
||||
}
|
||||
// return cached object
|
||||
else {
|
||||
return status.retVal;
|
||||
}
|
||||
}
|
||||
|
||||
retVal = invoker.invoke();
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
update(updates, retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions) {
|
||||
|
||||
if (!evictions.isEmpty()) {
|
||||
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : evictions) {
|
||||
if (context.isConditionPassing()) {
|
||||
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
|
||||
|
||||
// for each cache
|
||||
// lazy key initialization
|
||||
Object key = null;
|
||||
|
||||
for (Cache cache : context.getCaches()) {
|
||||
// cache-wide flush
|
||||
if (evictOp.isCacheWide()) {
|
||||
cache.clear();
|
||||
if (log) {
|
||||
logger.trace("Invalidating entire cache for definition " + evictOp + " on method " + context.method);
|
||||
}
|
||||
} else {
|
||||
// check key
|
||||
if (key == null) {
|
||||
key = context.generateKey();
|
||||
}
|
||||
if (log) {
|
||||
logger.trace("Invalidating cache key " + key + " for definition " + evictOp + " on method " + context.method);
|
||||
}
|
||||
cache.evict(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(
|
||||
cacheables.size());
|
||||
|
||||
boolean updateRequire = false;
|
||||
Object retVal = null;
|
||||
|
||||
if (!cacheables.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
boolean atLeastOnePassed = false;
|
||||
|
||||
for (CacheOperationContext context : cacheables) {
|
||||
if (context.isConditionPassing()) {
|
||||
atLeastOnePassed = true;
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for definition " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
|
||||
boolean localCacheHit = false;
|
||||
|
||||
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
|
||||
if (!updateRequire) {
|
||||
for (Cache cache : context.getCaches()) {
|
||||
Cache.ValueWrapper wrapper = cache.get(key);
|
||||
if (wrapper != null) {
|
||||
retVal = wrapper.get();
|
||||
localCacheHit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!localCacheHit) {
|
||||
updateRequire = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return a status only if at least on cacheable matched
|
||||
if (atLeastOnePassed) {
|
||||
return new CacheStatus(cUpdates, updateRequire, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class CacheStatus {
|
||||
// caches/key
|
||||
final Map<CacheOperationContext, Object> cUpdates;
|
||||
final boolean updateRequired;
|
||||
final Object retVal;
|
||||
|
||||
CacheStatus(Map<CacheOperationContext, Object> cUpdates, boolean updateRequired, Object retVal) {
|
||||
this.cUpdates = cUpdates;
|
||||
this.updateRequired = updateRequired;
|
||||
this.retVal = retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<CacheOperationContext, Object> inspectCacheUpdates(Collection<CacheOperationContext> updates) {
|
||||
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : updates) {
|
||||
if (context.isConditionPassing()) {
|
||||
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for definition " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache definition (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cUpdates;
|
||||
}
|
||||
|
||||
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
|
||||
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
|
||||
for (Cache cache : entry.getKey().getCaches()) {
|
||||
cache.put(entry.getValue(), retVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Collection<CacheOperationContext>> createOperationContext(Collection<CacheOperation> cacheOp,
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
Map<String, Collection<CacheOperationContext>> map = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
|
||||
|
||||
Collection<CacheOperationContext> cacheables = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> evicts = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> updates = new ArrayList<CacheOperationContext>();
|
||||
|
||||
for (CacheOperation cacheOperation : cacheOp) {
|
||||
CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass);
|
||||
|
||||
if (cacheOperation instanceof CacheableOperation) {
|
||||
cacheables.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CacheEvictOperation) {
|
||||
evicts.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CachePutOperation) {
|
||||
updates.add(opContext);
|
||||
}
|
||||
}
|
||||
|
||||
map.put(CACHEABLE, cacheables);
|
||||
map.put(EVICT, evicts);
|
||||
map.put(UPDATE, updates);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected class CacheOperationContext {
|
||||
|
||||
private final CacheOperation operation;
|
||||
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
// context passed around to avoid multiple creations
|
||||
private final EvaluationContext evalContext;
|
||||
|
||||
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target,
|
||||
Class<?> targetClass) {
|
||||
this.operation = operation;
|
||||
this.caches = CacheAspectSupport.this.getCaches(operation);
|
||||
this.target = target;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
|
||||
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
|
||||
}
|
||||
|
||||
protected boolean isConditionPassing() {
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the key for the given caching operation.
|
||||
* @return generated key (null if none can be generated)
|
||||
*/
|
||||
protected Object generateKey() {
|
||||
if (StringUtils.hasText(this.operation.getKey())) {
|
||||
return evaluator.key(this.operation.getKey(), this.method, this.evalContext);
|
||||
}
|
||||
return keyGenerator.generate(this.target, this.method, this.args);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,44 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'evict' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheEvictOperation extends CacheOperation {
|
||||
|
||||
private boolean cacheWide = false;
|
||||
|
||||
public void setCacheWide(boolean cacheWide) {
|
||||
this.cacheWide = cacheWide;
|
||||
}
|
||||
|
||||
public boolean isCacheWide() {
|
||||
return this.cacheWide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(",");
|
||||
sb.append(this.cacheWide);
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'evict' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheEvictOperation extends CacheOperation {
|
||||
|
||||
private boolean cacheWide = false;
|
||||
|
||||
public void setCacheWide(boolean cacheWide) {
|
||||
this.cacheWide = cacheWide;
|
||||
}
|
||||
|
||||
public boolean isCacheWide() {
|
||||
return this.cacheWide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(",");
|
||||
sb.append(this.cacheWide);
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +1,81 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Class describing the root object used during the expression evaluation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class CacheExpressionRootObject {
|
||||
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
|
||||
public CacheExpressionRootObject(
|
||||
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
Assert.notNull(method, "Method is required");
|
||||
Assert.notNull(targetClass, "targetClass is required");
|
||||
this.method = method;
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
this.args = args;
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
|
||||
public Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return this.method.getName();
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Class describing the root object used during the expression evaluation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class CacheExpressionRootObject {
|
||||
|
||||
private final Collection<Cache> caches;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
|
||||
public CacheExpressionRootObject(
|
||||
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
Assert.notNull(method, "Method is required");
|
||||
Assert.notNull(targetClass, "targetClass is required");
|
||||
this.method = method;
|
||||
this.target = target;
|
||||
this.targetClass = targetClass;
|
||||
this.args = args;
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
|
||||
public Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return this.method.getName();
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* AOP Alliance MethodInterceptor for declarative cache
|
||||
* management using the common Spring caching infrastructure
|
||||
* ({@link org.springframework.cache.Cache}).
|
||||
*
|
||||
* <p>Derives from the {@link CacheAspectSupport} class which
|
||||
* contains the integration with Spring's underlying caching API.
|
||||
* CacheInterceptor simply calls the relevant superclass methods
|
||||
* in the correct order.
|
||||
*
|
||||
* <p>CacheInterceptors are thread-safe.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
|
||||
|
||||
private static class ThrowableWrapper extends RuntimeException {
|
||||
private final Throwable original;
|
||||
|
||||
ThrowableWrapper(Throwable original) {
|
||||
this.original = original;
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
Invoker aopAllianceInvoker = new Invoker() {
|
||||
public Object invoke() {
|
||||
try {
|
||||
return invocation.proceed();
|
||||
} catch (Throwable ex) {
|
||||
throw new ThrowableWrapper(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
|
||||
} catch (ThrowableWrapper th) {
|
||||
throw th.original;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* AOP Alliance MethodInterceptor for declarative cache
|
||||
* management using the common Spring caching infrastructure
|
||||
* ({@link org.springframework.cache.Cache}).
|
||||
*
|
||||
* <p>Derives from the {@link CacheAspectSupport} class which
|
||||
* contains the integration with Spring's underlying caching API.
|
||||
* CacheInterceptor simply calls the relevant superclass methods
|
||||
* in the correct order.
|
||||
*
|
||||
* <p>CacheInterceptors are thread-safe.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
|
||||
|
||||
private static class ThrowableWrapper extends RuntimeException {
|
||||
private final Throwable original;
|
||||
|
||||
ThrowableWrapper(Throwable original) {
|
||||
this.original = original;
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
Invoker aopAllianceInvoker = new Invoker() {
|
||||
public Object invoke() {
|
||||
try {
|
||||
return invocation.proceed();
|
||||
} catch (Throwable ex) {
|
||||
throw new ThrowableWrapper(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
|
||||
} catch (ThrowableWrapper th) {
|
||||
throw th.original;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,128 +1,128 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class implementing {@link CacheOperation}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public abstract class CacheOperation {
|
||||
|
||||
private Set<String> cacheNames = Collections.emptySet();
|
||||
private String condition = "";
|
||||
private String key = "";
|
||||
private String name = "";
|
||||
|
||||
|
||||
public Set<String> getCacheNames() {
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setCacheName(String cacheName) {
|
||||
Assert.hasText(cacheName);
|
||||
this.cacheNames = Collections.singleton(cacheName);
|
||||
}
|
||||
|
||||
public void setCacheNames(String[] cacheNames) {
|
||||
Assert.notEmpty(cacheNames);
|
||||
this.cacheNames = new LinkedHashSet<String>(cacheNames.length);
|
||||
for (String string : cacheNames) {
|
||||
this.cacheNames.add(string);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCondition(String condition) {
|
||||
Assert.notNull(condition);
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Assert.notNull(key);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
Assert.hasText(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation compares the <code>toString()</code> results.
|
||||
* @see #toString()
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof CacheOperation && toString().equals(other.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns <code>toString()</code>'s hash code.
|
||||
* @see #toString()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifying description for this cache operation.
|
||||
* <p>Has to be overridden in subclasses for correct <code>equals</code>
|
||||
* and <code>hashCode</code> behavior. Alternatively, {@link #equals}
|
||||
* and {@link #hashCode} can be overridden themselves.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getOperationDescription().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifying description for this caching operation.
|
||||
* <p>Available to subclasses, for inclusion in their <code>toString()</code> result.
|
||||
*/
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("CacheDefinition[");
|
||||
result.append(this.name);
|
||||
result.append("] caches=");
|
||||
result.append(this.cacheNames);
|
||||
result.append(" | condition='");
|
||||
result.append(this.condition);
|
||||
result.append("' | key='");
|
||||
result.append(this.key);
|
||||
result.append("'");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class implementing {@link CacheOperation}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public abstract class CacheOperation {
|
||||
|
||||
private Set<String> cacheNames = Collections.emptySet();
|
||||
private String condition = "";
|
||||
private String key = "";
|
||||
private String name = "";
|
||||
|
||||
|
||||
public Set<String> getCacheNames() {
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setCacheName(String cacheName) {
|
||||
Assert.hasText(cacheName);
|
||||
this.cacheNames = Collections.singleton(cacheName);
|
||||
}
|
||||
|
||||
public void setCacheNames(String[] cacheNames) {
|
||||
Assert.notEmpty(cacheNames);
|
||||
this.cacheNames = new LinkedHashSet<String>(cacheNames.length);
|
||||
for (String string : cacheNames) {
|
||||
this.cacheNames.add(string);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCondition(String condition) {
|
||||
Assert.notNull(condition);
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Assert.notNull(key);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
Assert.hasText(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation compares the {@code toString()} results.
|
||||
* @see #toString()
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof CacheOperation && toString().equals(other.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns {@code toString()}'s hash code.
|
||||
* @see #toString()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifying description for this cache operation.
|
||||
* <p>Has to be overridden in subclasses for correct {@code equals}
|
||||
* and {@code hashCode} behavior. Alternatively, {@link #equals}
|
||||
* and {@link #hashCode} can be overridden themselves.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getOperationDescription().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifying description for this caching operation.
|
||||
* <p>Available to subclasses, for inclusion in their {@code toString()} result.
|
||||
*/
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("CacheDefinition[");
|
||||
result.append(this.name);
|
||||
result.append("] caches=");
|
||||
result.append(this.cacheNames);
|
||||
result.append(" | condition='");
|
||||
result.append(this.condition);
|
||||
result.append("' | key='");
|
||||
result.append(this.key);
|
||||
result.append("'");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Interface used by CacheInterceptor. Implementations know
|
||||
* how to source cache operation attributes, whether from configuration,
|
||||
* metadata attributes at source level, or anywhere else.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheOperationSource {
|
||||
|
||||
/**
|
||||
* Return the cache operation definition for this method,
|
||||
* or <code>null</code> if the method contains no "cacheable" annotations.
|
||||
* @param method the method to introspect
|
||||
* @param targetClass the target class (may be <code>null</code>,
|
||||
* in which case the declaring class of the method must be used)
|
||||
* @return {@link CacheOperation} the matching cache operation,
|
||||
* or <code>null</code> if none found
|
||||
*/
|
||||
Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Interface used by CacheInterceptor. Implementations know
|
||||
* how to source cache operation attributes, whether from configuration,
|
||||
* metadata attributes at source level, or anywhere else.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface CacheOperationSource {
|
||||
|
||||
/**
|
||||
* Return the cache operation definition for this method,
|
||||
* or {@code null} if the method contains no "cacheable" annotations.
|
||||
* @param method the method to introspect
|
||||
* @param targetClass the target class (may be {@code null},
|
||||
* in which case the declaring class of the method must be used)
|
||||
* @return {@link CacheOperation} the matching cache operation,
|
||||
* or {@code null} if none found
|
||||
*/
|
||||
Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A Pointcut that matches if the underlying {@link CacheOperationSource}
|
||||
* has an attribute for a given method.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
CacheOperationSource cas = getCacheOperationSource();
|
||||
return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof CacheOperationSourcePointcut)) {
|
||||
return false;
|
||||
}
|
||||
CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(getCacheOperationSource(),
|
||||
otherPc.getCacheOperationSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return CacheOperationSourcePointcut.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + getCacheOperationSource();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the underlying CacheOperationDefinitionSource (may be <code>null</code>).
|
||||
* To be implemented by subclasses.
|
||||
*/
|
||||
protected abstract CacheOperationSource getCacheOperationSource();
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A Pointcut that matches if the underlying {@link CacheOperationSource}
|
||||
* has an attribute for a given method.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
CacheOperationSource cas = getCacheOperationSource();
|
||||
return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof CacheOperationSourcePointcut)) {
|
||||
return false;
|
||||
}
|
||||
CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(getCacheOperationSource(),
|
||||
otherPc.getCacheOperationSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return CacheOperationSourcePointcut.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + getCacheOperationSource();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the underlying CacheOperationDefinitionSource (may be {@code null}).
|
||||
* To be implemented by subclasses.
|
||||
*/
|
||||
protected abstract CacheOperationSource getCacheOperationSource();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,79 +1,79 @@
|
|||
/*
|
||||
* 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 org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Proxy factory bean for simplified declarative caching handling.
|
||||
* This is a convenient alternative to a standard AOP
|
||||
* {@link org.springframework.aop.framework.ProxyFactoryBean}
|
||||
* with a separate {@link CachingInterceptor} definition.
|
||||
*
|
||||
* <p>This class is designed to facilitate declarative cache demarcation: namely, wrapping
|
||||
* a singleton target object with a caching proxy, proxying all the interfaces that the
|
||||
* target implements. Exists primarily for third-party framework integration.
|
||||
* <strong>Users should favor the {@code cache:} XML namespace
|
||||
* {@link org.springframework.cache.annotation.Cacheable @Cacheable} annotation.</strong>
|
||||
* See the <a href="http://bit.ly/p9rIvx">declarative annotation-based caching</a> section
|
||||
* of the Spring reference documentation for more information.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @see org.springframework.aop.framework.ProxyFactoryBean
|
||||
* @see CachingInterceptor
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
|
||||
|
||||
private final CacheInterceptor cachingInterceptor = new CacheInterceptor();
|
||||
private Pointcut pointcut;
|
||||
|
||||
/**
|
||||
* Set a pointcut, i.e a bean that can cause conditional invocation
|
||||
* of the CacheInterceptor depending on method and attributes passed.
|
||||
* Note: Additional interceptors are always invoked.
|
||||
* @see #setPreInterceptors
|
||||
* @see #setPostInterceptors
|
||||
*/
|
||||
public void setPointcut(Pointcut pointcut) {
|
||||
this.pointcut = pointcut;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object createMainInterceptor() {
|
||||
this.cachingInterceptor.afterPropertiesSet();
|
||||
if (this.pointcut != null) {
|
||||
return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor);
|
||||
} else {
|
||||
// Rely on default pointcut.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the caching attribute source which is used to find the cache operation
|
||||
* definition.
|
||||
*
|
||||
* @param cacheDefinitionSources cache definition sources
|
||||
*/
|
||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Proxy factory bean for simplified declarative caching handling.
|
||||
* This is a convenient alternative to a standard AOP
|
||||
* {@link org.springframework.aop.framework.ProxyFactoryBean}
|
||||
* with a separate {@link CachingInterceptor} definition.
|
||||
*
|
||||
* <p>This class is designed to facilitate declarative cache demarcation: namely, wrapping
|
||||
* a singleton target object with a caching proxy, proxying all the interfaces that the
|
||||
* target implements. Exists primarily for third-party framework integration.
|
||||
* <strong>Users should favor the {@code cache:} XML namespace
|
||||
* {@link org.springframework.cache.annotation.Cacheable @Cacheable} annotation.</strong>
|
||||
* See the <a href="http://bit.ly/p9rIvx">declarative annotation-based caching</a> section
|
||||
* of the Spring reference documentation for more information.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @see org.springframework.aop.framework.ProxyFactoryBean
|
||||
* @see CachingInterceptor
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
|
||||
|
||||
private final CacheInterceptor cachingInterceptor = new CacheInterceptor();
|
||||
private Pointcut pointcut;
|
||||
|
||||
/**
|
||||
* Set a pointcut, i.e a bean that can cause conditional invocation
|
||||
* of the CacheInterceptor depending on method and attributes passed.
|
||||
* Note: Additional interceptors are always invoked.
|
||||
* @see #setPreInterceptors
|
||||
* @see #setPostInterceptors
|
||||
*/
|
||||
public void setPointcut(Pointcut pointcut) {
|
||||
this.pointcut = pointcut;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object createMainInterceptor() {
|
||||
this.cachingInterceptor.afterPropertiesSet();
|
||||
if (this.pointcut != null) {
|
||||
return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor);
|
||||
} else {
|
||||
// Rely on default pointcut.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the caching attribute source which is used to find the cache operation
|
||||
* definition.
|
||||
*
|
||||
* @param cacheDefinitionSources cache definition sources
|
||||
*/
|
||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
* Copyright 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;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'put' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CachePutOperation extends CacheOperation {
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'put' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CachePutOperation extends CacheOperation {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'cacheable' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheableOperation extends CacheOperation {
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* Class describing a cache 'cacheable' operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CacheableOperation extends CacheOperation {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,69 +1,69 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheOperationSource} implementation that iterates
|
||||
* over a given array of {@link CacheOperationSource} instances.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CompositeCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
private final CacheOperationSource[] cacheOperationSources;
|
||||
|
||||
/**
|
||||
* Create a new CompositeCacheOperationSource for the given sources.
|
||||
* @param cacheOperationSources the CacheOperationSource instances to combine
|
||||
*/
|
||||
public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty");
|
||||
this.cacheOperationSources = cacheOperationSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines.
|
||||
*/
|
||||
public final CacheOperationSource[] getCacheOperationSources() {
|
||||
return this.cacheOperationSources;
|
||||
}
|
||||
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
for (CacheOperationSource source : this.cacheOperationSources) {
|
||||
Collection<CacheOperation> cacheOperations = source.getCacheOperations(method, targetClass);
|
||||
if (cacheOperations != null) {
|
||||
if (ops == null) {
|
||||
ops = new ArrayList<CacheOperation>();
|
||||
}
|
||||
|
||||
ops.addAll(cacheOperations);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheOperationSource} implementation that iterates
|
||||
* over a given array of {@link CacheOperationSource} instances.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CompositeCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
private final CacheOperationSource[] cacheOperationSources;
|
||||
|
||||
/**
|
||||
* Create a new CompositeCacheOperationSource for the given sources.
|
||||
* @param cacheOperationSources the CacheOperationSource instances to combine
|
||||
*/
|
||||
public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty");
|
||||
this.cacheOperationSources = cacheOperationSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines.
|
||||
*/
|
||||
public final CacheOperationSource[] getCacheOperationSources() {
|
||||
return this.cacheOperationSources;
|
||||
}
|
||||
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
for (CacheOperationSource source : this.cacheOperationSources) {
|
||||
Collection<CacheOperation> cacheOperations = source.getCacheOperations(method, targetClass);
|
||||
if (cacheOperations != null) {
|
||||
if (ops == null) {
|
||||
ops = new ArrayList<CacheOperation>();
|
||||
}
|
||||
|
||||
ops.addAll(cacheOperations);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,53 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
/**
|
||||
* Default key generator. Returns {@value #NO_PARAM_KEY} if no parameters are provided,
|
||||
* the parameter itself if only one is given or a hash code computed from all given
|
||||
* parameters' hash code values. Uses the constant value {@value #NULL_PARAM_KEY} for any
|
||||
* {@code null} parameters given.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultKeyGenerator implements KeyGenerator {
|
||||
|
||||
public static final int NO_PARAM_KEY = 0;
|
||||
public static final int NULL_PARAM_KEY = 53;
|
||||
|
||||
public Object generate(Object target, Method method, Object... params) {
|
||||
if (params.length == 1) {
|
||||
return (params[0] == null ? NULL_PARAM_KEY : params[0]);
|
||||
}
|
||||
if (params.length == 0) {
|
||||
return NO_PARAM_KEY;
|
||||
}
|
||||
int hashCode = 17;
|
||||
for (Object object : params) {
|
||||
hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
|
||||
}
|
||||
return Integer.valueOf(hashCode);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
/**
|
||||
* Default key generator. Returns {@value #NO_PARAM_KEY} if no
|
||||
* parameters are provided, the parameter itself if only one is given or
|
||||
* a hash code computed from all given parameters' hash code values.
|
||||
* Uses the constant value {@value #NULL_PARAM_KEY} for any
|
||||
* {@code null} parameters given.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultKeyGenerator implements KeyGenerator {
|
||||
|
||||
public static final int NO_PARAM_KEY = 0;
|
||||
public static final int NULL_PARAM_KEY = 53;
|
||||
|
||||
public Object generate(Object target, Method method, Object... params) {
|
||||
if (params.length == 1) {
|
||||
return (params[0] == null ? NULL_PARAM_KEY : params[0]);
|
||||
}
|
||||
if (params.length == 0) {
|
||||
return NO_PARAM_KEY;
|
||||
}
|
||||
int hashCode = 17;
|
||||
for (Object object : params) {
|
||||
hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
|
||||
}
|
||||
return Integer.valueOf(hashCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +1,81 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Utility class handling the SpEL expression parsing.
|
||||
* Meant to be used as a reusable, thread-safe component.
|
||||
*
|
||||
* <p>Performs internal caching for performance reasons.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class ExpressionEvaluator {
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
// shared param discoverer since it caches data internally
|
||||
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression condExp = this.conditionCache.get(method);
|
||||
if (condExp == null) {
|
||||
condExp = this.parser.parseExpression(conditionExpression);
|
||||
this.conditionCache.put(method, condExp);
|
||||
}
|
||||
return condExp.getValue(evalContext, boolean.class);
|
||||
}
|
||||
|
||||
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression keyExp = this.keyCache.get(method);
|
||||
if (keyExp == null) {
|
||||
keyExp = this.parser.parseExpression(keyExpression);
|
||||
this.keyCache.put(method, keyExp);
|
||||
}
|
||||
return keyExp.getValue(evalContext);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Utility class handling the SpEL expression parsing.
|
||||
* Meant to be used as a reusable, thread-safe component.
|
||||
*
|
||||
* <p>Performs internal caching for performance reasons.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class ExpressionEvaluator {
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
// shared param discoverer since it caches data internally
|
||||
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private Map<Method, Expression> conditionCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Expression> keyCache = new ConcurrentHashMap<Method, Expression>();
|
||||
|
||||
private Map<Method, Method> targetMethodCache = new ConcurrentHashMap<Method, Method>();
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression condExp = this.conditionCache.get(method);
|
||||
if (condExp == null) {
|
||||
condExp = this.parser.parseExpression(conditionExpression);
|
||||
this.conditionCache.put(method, condExp);
|
||||
}
|
||||
return condExp.getValue(evalContext, boolean.class);
|
||||
}
|
||||
|
||||
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
|
||||
Expression keyExp = this.keyCache.get(method);
|
||||
if (keyExp == null) {
|
||||
keyExp = this.parser.parseExpression(keyExpression);
|
||||
this.keyCache.put(method, keyExp);
|
||||
}
|
||||
return keyExp.getValue(evalContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,33 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Cache key generator. Used for creating a key based on the given method
|
||||
* (used as context) and its parameters.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface KeyGenerator {
|
||||
|
||||
Object generate(Object target, Method method, Object... params);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Cache key generator. Used for creating a key based on the given method
|
||||
* (used as context) and its parameters.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface KeyGenerator {
|
||||
|
||||
Object generate(Object target, Method method, Object... params);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,111 +1,111 @@
|
|||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Evaluation context class that adds a method parameters as SpEL variables,
|
||||
* in a lazy manner. The lazy nature eliminates unneeded parsing of classes
|
||||
* byte code for parameter discovery.
|
||||
*
|
||||
* <p>To limit the creation of objects, an ugly constructor is used (rather then
|
||||
* a dedicated 'closure'-like class for deferred execution).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private final ParameterNameDiscoverer paramDiscoverer;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Map<Method, Method> methodCache;
|
||||
|
||||
private boolean paramLoaded = false;
|
||||
|
||||
|
||||
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
||||
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) {
|
||||
super(rootObject);
|
||||
|
||||
this.paramDiscoverer = paramDiscoverer;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
this.targetClass = targetClass;
|
||||
this.methodCache = methodCache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the param information only when needed.
|
||||
*/
|
||||
@Override
|
||||
public Object lookupVariable(String name) {
|
||||
Object variable = super.lookupVariable(name);
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
if (!this.paramLoaded) {
|
||||
loadArgsAsVariables();
|
||||
this.paramLoaded = true;
|
||||
variable = super.lookupVariable(name);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
private void loadArgsAsVariables() {
|
||||
// shortcut if no args need to be loaded
|
||||
if (ObjectUtils.isEmpty(this.args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method targetMethod = this.methodCache.get(this.method);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = this.method;
|
||||
}
|
||||
this.methodCache.put(this.method, targetMethod);
|
||||
}
|
||||
|
||||
// save arguments as indexed variables
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
setVariable("p" + i, this.args[i]);
|
||||
}
|
||||
|
||||
String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod);
|
||||
// save parameter names (if discovered)
|
||||
if (parameterNames != null) {
|
||||
for (int i = 0; i < parameterNames.length; i++) {
|
||||
setVariable(parameterNames[i], this.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Evaluation context class that adds a method parameters as SpEL
|
||||
* variables, in a lazy manner. The lazy nature eliminates unneeded
|
||||
* parsing of classes byte code for parameter discovery.
|
||||
*
|
||||
* <p>To limit the creation of objects, an ugly constructor is used
|
||||
* (rather then a dedicated 'closure'-like class for deferred execution).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private final ParameterNameDiscoverer paramDiscoverer;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Map<Method, Method> methodCache;
|
||||
|
||||
private boolean paramLoaded = false;
|
||||
|
||||
|
||||
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
|
||||
Object[] args, Class<?> targetClass, Map<Method, Method> methodCache) {
|
||||
super(rootObject);
|
||||
|
||||
this.paramDiscoverer = paramDiscoverer;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
this.targetClass = targetClass;
|
||||
this.methodCache = methodCache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the param information only when needed.
|
||||
*/
|
||||
@Override
|
||||
public Object lookupVariable(String name) {
|
||||
Object variable = super.lookupVariable(name);
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
if (!this.paramLoaded) {
|
||||
loadArgsAsVariables();
|
||||
this.paramLoaded = true;
|
||||
variable = super.lookupVariable(name);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
private void loadArgsAsVariables() {
|
||||
// shortcut if no args need to be loaded
|
||||
if (ObjectUtils.isEmpty(this.args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method targetMethod = this.methodCache.get(this.method);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = this.method;
|
||||
}
|
||||
this.methodCache.put(this.method, targetMethod);
|
||||
}
|
||||
|
||||
// save arguments as indexed variables
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
setVariable("p" + i, this.args[i]);
|
||||
}
|
||||
|
||||
String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod);
|
||||
// save parameter names (if discovered)
|
||||
if (parameterNames != null) {
|
||||
for (int i = 0; i < parameterNames.length; i++) {
|
||||
setVariable(parameterNames[i], this.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,128 +1,128 @@
|
|||
/*
|
||||
* Copyright 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.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link CacheOperationSource} implementation that
|
||||
* allows attributes to be matched by registered name.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>Static for optimal serialization.
|
||||
*/
|
||||
protected static final Log logger = LogFactory.getLog(NameMatchCacheOperationSource.class);
|
||||
|
||||
/** Keys are method names; values are TransactionAttributes */
|
||||
private Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<String, Collection<CacheOperation>>();
|
||||
|
||||
/**
|
||||
* Set a name/attribute map, consisting of method names
|
||||
* (e.g. "myMethod") and CacheOperation instances
|
||||
* (or Strings to be converted to CacheOperation instances).
|
||||
* @see CacheOperation
|
||||
* @see CacheOperationEditor
|
||||
*/
|
||||
public void setNameMap(Map<String, Collection<CacheOperation>> nameMap) {
|
||||
for (Map.Entry<String, Collection<CacheOperation>> entry : nameMap.entrySet()) {
|
||||
addCacheMethod(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attribute for a cacheable method.
|
||||
* <p>Method names can be exact matches, or of the pattern "xxx*",
|
||||
* "*xxx" or "*xxx*" for matching multiple methods.
|
||||
* @param methodName the name of the method
|
||||
* @param ops operation associated with the method
|
||||
*/
|
||||
public void addCacheMethod(String methodName, Collection<CacheOperation> ops) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding method [" + methodName + "] with cache operations [" + ops + "]");
|
||||
}
|
||||
this.nameMap.put(methodName, ops);
|
||||
}
|
||||
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
// look for direct name match
|
||||
String methodName = method.getName();
|
||||
Collection<CacheOperation> ops = this.nameMap.get(methodName);
|
||||
|
||||
if (ops == null) {
|
||||
// Look for most specific name match.
|
||||
String bestNameMatch = null;
|
||||
for (String mappedName : this.nameMap.keySet()) {
|
||||
if (isMatch(methodName, mappedName)
|
||||
&& (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
|
||||
ops = this.nameMap.get(mappedName);
|
||||
bestNameMatch = mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the given method name matches the mapped name.
|
||||
* <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
|
||||
* as well as direct equality. Can be overridden in subclasses.
|
||||
* @param methodName the method name of the class
|
||||
* @param mappedName the name in the descriptor
|
||||
* @return if the names match
|
||||
* @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
|
||||
*/
|
||||
protected boolean isMatch(String methodName, String mappedName) {
|
||||
return PatternMatchUtils.simpleMatch(mappedName, methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof NameMatchCacheOperationSource)) {
|
||||
return false;
|
||||
}
|
||||
NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other;
|
||||
return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NameMatchCacheOperationSource.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.nameMap;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 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.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link CacheOperationSource} implementation that
|
||||
* allows attributes to be matched by registered name.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>Static for optimal serialization.
|
||||
*/
|
||||
protected static final Log logger = LogFactory.getLog(NameMatchCacheOperationSource.class);
|
||||
|
||||
/** Keys are method names; values are TransactionAttributes */
|
||||
private Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<String, Collection<CacheOperation>>();
|
||||
|
||||
/**
|
||||
* Set a name/attribute map, consisting of method names
|
||||
* (e.g. "myMethod") and CacheOperation instances
|
||||
* (or Strings to be converted to CacheOperation instances).
|
||||
* @see CacheOperation
|
||||
* @see CacheOperationEditor
|
||||
*/
|
||||
public void setNameMap(Map<String, Collection<CacheOperation>> nameMap) {
|
||||
for (Map.Entry<String, Collection<CacheOperation>> entry : nameMap.entrySet()) {
|
||||
addCacheMethod(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attribute for a cacheable method.
|
||||
* <p>Method names can be exact matches, or of the pattern "xxx*",
|
||||
* "*xxx" or "*xxx*" for matching multiple methods.
|
||||
* @param methodName the name of the method
|
||||
* @param ops operation associated with the method
|
||||
*/
|
||||
public void addCacheMethod(String methodName, Collection<CacheOperation> ops) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding method [" + methodName + "] with cache operations [" + ops + "]");
|
||||
}
|
||||
this.nameMap.put(methodName, ops);
|
||||
}
|
||||
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
// look for direct name match
|
||||
String methodName = method.getName();
|
||||
Collection<CacheOperation> ops = this.nameMap.get(methodName);
|
||||
|
||||
if (ops == null) {
|
||||
// Look for most specific name match.
|
||||
String bestNameMatch = null;
|
||||
for (String mappedName : this.nameMap.keySet()) {
|
||||
if (isMatch(methodName, mappedName)
|
||||
&& (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
|
||||
ops = this.nameMap.get(mappedName);
|
||||
bestNameMatch = mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the given method name matches the mapped name.
|
||||
* <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
|
||||
* as well as direct equality. Can be overridden in subclasses.
|
||||
* @param methodName the method name of the class
|
||||
* @param mappedName the name in the descriptor
|
||||
* @return if the names match
|
||||
* @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
|
||||
*/
|
||||
protected boolean isMatch(String methodName, String mappedName) {
|
||||
return PatternMatchUtils.simpleMatch(mappedName, methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof NameMatchCacheOperationSource)) {
|
||||
return false;
|
||||
}
|
||||
NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other;
|
||||
return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NameMatchCacheOperationSource.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.nameMap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
/**
|
||||
* AOP-based solution for declarative caching demarcation.
|
||||
* Builds on the AOP infrastructure in org.springframework.aop.framework.
|
||||
* Any POJO can be cache advised with Spring.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
/**
|
||||
* AOP-based solution for declarative caching demarcation.
|
||||
* Builds on the AOP infrastructure in org.springframework.aop.framework.
|
||||
* Any POJO can be cache-advised with Spring.
|
||||
*/
|
||||
package org.springframework.cache.interceptor;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/**
|
||||
* Spring's generic cache abstraction.
|
||||
* Concrete implementations are provided in the subpackages.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cache;
|
||||
|
||||
/**
|
||||
* Spring's generic cache abstraction.
|
||||
* Concrete implementations are provided in the subpackages.
|
||||
*/
|
||||
package org.springframework.cache;
|
||||
|
|
|
|||
|
|
@ -1,78 +1,79 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class implementing the common CacheManager methods.
|
||||
* Useful for 'static' environments where the backing caches do not change.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
|
||||
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
private Set<String> cacheNames = new LinkedHashSet<String>();
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Collection<? extends Cache> caches = loadCaches();
|
||||
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
|
||||
this.cacheMap.clear();
|
||||
|
||||
// preserve the initial order of the cache names
|
||||
for (Cache cache : caches) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addCache(Cache cache) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
|
||||
public Cache getCache(String name) {
|
||||
return this.cacheMap.get(name);
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
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<? extends Cache> loadCaches();
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class implementing the common {@link CacheManager}
|
||||
* methods. Useful for 'static' environments where the backing caches do
|
||||
* not change.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
|
||||
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
private Set<String> cacheNames = new LinkedHashSet<String>();
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Collection<? extends Cache> caches = loadCaches();
|
||||
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
|
||||
this.cacheMap.clear();
|
||||
|
||||
// preserve the initial order of the cache names
|
||||
for (Cache cache : caches) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addCache(Cache cache) {
|
||||
this.cacheMap.put(cache.getName(), cache);
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
|
||||
public Cache getCache(String name) {
|
||||
return this.cacheMap.get(name);
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
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<? extends Cache> loadCaches();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +1,87 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheManager} implementation that iterates
|
||||
* over a given collection of {@link CacheManager} instances.
|
||||
*
|
||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||
* the cache declarations without a backing store.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
|
||||
private List<CacheManager> cacheManagers;
|
||||
|
||||
private boolean fallbackToNoOpCache = false;
|
||||
|
||||
|
||||
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
|
||||
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
|
||||
this.cacheManagers = new ArrayList<CacheManager>();
|
||||
this.cacheManagers.addAll(cacheManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||
* In this case, any <code>getCache</code> requests not handled by the configured cache managers will
|
||||
* be automatically handled by the {@link NoOpCacheManager} (and hence never return <code>null</code>).
|
||||
*/
|
||||
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||
this.fallbackToNoOpCache = fallbackToNoOpCache;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.fallbackToNoOpCache) {
|
||||
this.cacheManagers.add(new NoOpCacheManager());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Cache getCache(String name) {
|
||||
for (CacheManager cacheManager : this.cacheManagers) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (CacheManager manager : this.cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheManager} implementation that iterates
|
||||
* over a given collection of {@link CacheManager} instances.
|
||||
*
|
||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||
* the cache declarations without a backing store.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
|
||||
private List<CacheManager> cacheManagers;
|
||||
|
||||
private boolean fallbackToNoOpCache = false;
|
||||
|
||||
|
||||
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
|
||||
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
|
||||
this.cacheManagers = new ArrayList<CacheManager>();
|
||||
this.cacheManagers.addAll(cacheManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||
* In this case, any {@code getCache} requests not handled by the configured cache managers will
|
||||
* be automatically handled by the {@link NoOpCacheManager} (and hence never return {@code null}).
|
||||
*/
|
||||
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||
this.fallbackToNoOpCache = fallbackToNoOpCache;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.fallbackToNoOpCache) {
|
||||
this.cacheManagers.add(new NoOpCacheManager());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Cache getCache(String name) {
|
||||
for (CacheManager cacheManager : this.cacheManagers) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (CacheManager manager : this.cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,100 +1,101 @@
|
|||
/*
|
||||
* Copyright 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* A basic, no operation {@link CacheManager} implementation suitable for disabling caching,
|
||||
* typically used for backing cache declarations without an actual backing store.
|
||||
*
|
||||
* <p>Will simply accept any items into the cache not actually storing them.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
* @see CompositeCacheManager
|
||||
*/
|
||||
public class NoOpCacheManager implements CacheManager {
|
||||
|
||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
||||
private Set<String> names = new LinkedHashSet<String>();
|
||||
|
||||
private static class NoOpCache implements Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
public NoOpCache(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This implementation always returns a {@link Cache} implementation that will not
|
||||
* store items. Additionally, the request cache will be remembered by the manager for consistency.
|
||||
*/
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = caches.get(name);
|
||||
if (cache == null) {
|
||||
caches.putIfAbsent(name, new NoOpCache(name));
|
||||
synchronized (names) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
return caches.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This implementation returns the name of the caches previously requested.
|
||||
*/
|
||||
public Collection<String> getCacheNames() {
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* A basic, no operation {@link CacheManager} implementation suitable
|
||||
* for disabling caching, typically used for backing cache declarations
|
||||
* without an actual backing store.
|
||||
*
|
||||
* <p>Will simply accept any items into the cache not actually storing them.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
* @see CompositeCacheManager
|
||||
*/
|
||||
public class NoOpCacheManager implements CacheManager {
|
||||
|
||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
||||
private Set<String> names = new LinkedHashSet<String>();
|
||||
|
||||
private static class NoOpCache implements Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
public NoOpCache(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
public void evict(Object key) {
|
||||
}
|
||||
|
||||
public ValueWrapper get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This implementation always returns a {@link Cache} implementation that will not
|
||||
* store items. Additionally, the request cache will be remembered by the manager for consistency.
|
||||
*/
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = caches.get(name);
|
||||
if (cache == null) {
|
||||
caches.putIfAbsent(name, new NoOpCache(name));
|
||||
synchronized (names) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
return caches.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This implementation returns the name of the caches previously requested.
|
||||
*/
|
||||
public Collection<String> getCacheNames() {
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +1,46 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Simple cache manager working against a given collection of caches.
|
||||
* Useful for testing or simple caching declarations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SimpleCacheManager extends AbstractCacheManager {
|
||||
|
||||
private Collection<? extends Cache> caches;
|
||||
|
||||
/**
|
||||
* Specify the collection of Cache instances to use for this CacheManager.
|
||||
*/
|
||||
public void setCaches(Collection<? extends Cache> caches) {
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<? extends Cache> loadCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Simple cache manager working against a given collection of caches.
|
||||
* Useful for testing or simple caching declarations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SimpleCacheManager extends AbstractCacheManager {
|
||||
|
||||
private Collection<? extends Cache> caches;
|
||||
|
||||
/**
|
||||
* Specify the collection of Cache instances to use for this CacheManager.
|
||||
*/
|
||||
public void setCaches(Collection<? extends Cache> caches) {
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<? extends Cache> loadCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,39 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.springframework.cache.Cache.ValueWrapper;
|
||||
|
||||
/**
|
||||
* Straightforward implementation of {@link org.springframework.cache.Cache.ValueWrapper}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ValueWrapperImpl implements ValueWrapper {
|
||||
|
||||
private final Object value;
|
||||
|
||||
public ValueWrapperImpl(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.springframework.cache.Cache.ValueWrapper;
|
||||
|
||||
/**
|
||||
* Straightforward implementation of {@link org.springframework.cache.Cache.ValueWrapper}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ValueWrapperImpl implements ValueWrapper {
|
||||
|
||||
private final Object value;
|
||||
|
||||
public ValueWrapperImpl(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/**
|
||||
* Support classes for the the org.springframework.cache package.
|
||||
* Provides abstract classes for cache managers and caches.
|
||||
*/
|
||||
package org.springframework.cache.support;
|
||||
|
||||
/**
|
||||
* Support classes for the the org.springframework.cache package.
|
||||
* Provides abstract classes for cache managers and caches.
|
||||
*/
|
||||
package org.springframework.cache.support;
|
||||
|
|
|
|||
Loading…
Reference in New Issue