diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java
new file mode 100644
index 00000000000..a8ef94fbd31
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cache.annotation;
+
+import java.io.Serializable;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+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.
+ *
+ *
This class reads Spring's JDK 1.5+ {@link Cacheable} 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
+ */
+@SuppressWarnings("serial")
+public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements
+ Serializable {
+
+ private final boolean publicMethodsOnly;
+
+ private final Set annotationParsers;
+
+ /**
+ * Create a default AnnotationCacheOperationSource, supporting
+ * public methods that carry the Cacheable and CacheEvict
+ * annotations.
+ */
+ public AnnotationCacheOperationSource() {
+ this(true);
+ }
+
+ /**
+ * Create a custom AnnotationCacheOperationSource, supporting
+ * public methods that carry the Cacheable and
+ * CacheEvict 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(1);
+ this.annotationParsers.add(new SpringCachingAnnotationParser());
+ }
+
+ /**
+ * 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 parsers = new LinkedHashSet(annotationParsers.length);
+ Collections.addAll(parsers, annotationParsers);
+ this.annotationParsers = parsers;
+ }
+
+ @Override
+ protected CacheOperation findCacheOperation(Class> clazz) {
+ return determineCacheOperation(clazz);
+ }
+
+ @Override
+ protected CacheOperation findCacheOperation(Method method) {
+ return determineCacheOperation(method);
+ }
+
+ /**
+ * Determine the cache operation definition for the given method or class.
+ *
This implementation delegates to configured
+ * {@link CacheAnnotationParser CacheAnnotationParsers}
+ * for parsing known annotations into Spring's metadata attribute class.
+ * Returns null if it's not cacheable.
+ *
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 null if none was found
+ */
+ protected CacheOperation determineCacheOperation(AnnotatedElement ae) {
+ for (CacheAnnotationParser annotationParser : this.annotationParsers) {
+ CacheOperation attr = annotationParser.parseCacheAnnotation(ae);
+ if (attr != null) {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * By default, only public methods can be made cacheable.
+ */
+ @Override
+ protected boolean allowPublicMethodsOnly() {
+ return this.publicMethodsOnly;
+ }
+}
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java
new file mode 100644
index 00000000000..687ec82b635
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cache.interceptor;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+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.
+ *
+ *
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.
+ *
+ *
This implementation caches attributes by method after they are first used.
+ * If it is ever desirable to allow dynamic changing of cacheable attributes
+ * (which is very unlikely), caching could be made configurable.
+
+ * @author Costin Leau
+ * @see org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
+ */
+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 CacheOperation NULL_CACHING_ATTRIBUTE = new CacheUpdateOperation();
+
+ /**
+ * Logger available to subclasses.
+ *
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).
+ *
As this base class is not marked Serializable, the cache will be recreated
+ * after serialization - provided that the concrete subclass is Serializable.
+ */
+ final Map