From 9952973e01790784b54fb804be07b849b1bc76f4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 21 May 2014 08:32:46 +0200 Subject: [PATCH] Add missing cache-resolver attribute Prior to this commit, CacheResolver could not be configured through the XML namespace (i.e. cache:annotation-driven). This is now the case. Issue: SPR-11490 --- .../config/JCacheNamespaceDrivenTests.java | 14 +++++++- .../config/jCacheNamespaceDriven-resolver.xml | 31 ++++++++++++++++++ .../cache/annotation/CachingConfigurer.java | 8 +++-- ...tationDrivenCacheBeanDefinitionParser.java | 25 +++++++++++---- .../interceptor/SimpleCacheResolver.java | 3 ++ .../cache/config/spring-cache-4.1.xsd | 32 ++++++++++++++++--- .../AnnotationNamespaceDrivenTests.java | 21 ++++++++++++ ...nDrivenCacheNamespace-manager-resolver.xml | 22 +++++++++++++ ...nnotationDrivenCacheNamespace-resolver.xml | 22 +++++++++++++ src/asciidoc/index.adoc | 13 ++++++-- 10 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 spring-context-support/src/test/resources/org/springframework/cache/jcache/config/jCacheNamespaceDriven-resolver.xml create mode 100644 spring-context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace-manager-resolver.xml create mode 100644 spring-context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace-resolver.xml diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java index 7391c8661d..0cdef3f159 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java @@ -16,13 +16,15 @@ package org.springframework.cache.jcache.config; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.*; import org.junit.Test; import org.springframework.cache.interceptor.CacheErrorHandler; +import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource; import org.springframework.cache.jcache.interceptor.JCacheInterceptor; import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; /** @@ -36,6 +38,16 @@ public class JCacheNamespaceDrivenTests extends AbstractJCacheAnnotationTests { "/org/springframework/cache/jcache/config/jCacheNamespaceDriven.xml"); } + @Test + public void cacheResolver() { + ConfigurableApplicationContext context = new GenericXmlApplicationContext( + "/org/springframework/cache/jcache/config/jCacheNamespaceDriven-resolver.xml"); + + DefaultJCacheOperationSource ci = context.getBean(DefaultJCacheOperationSource.class); + assertSame(context.getBean("cacheResolver"), ci.getDefaultCacheResolver()); + context.close(); + } + @Test public void testCacheErrorHandler() { JCacheInterceptor ci = ctx.getBean(JCacheInterceptor.class); diff --git a/spring-context-support/src/test/resources/org/springframework/cache/jcache/config/jCacheNamespaceDriven-resolver.xml b/spring-context-support/src/test/resources/org/springframework/cache/jcache/config/jCacheNamespaceDriven-resolver.xml new file mode 100644 index 0000000000..9c3c96360d --- /dev/null +++ b/spring-context-support/src/test/resources/org/springframework/cache/jcache/config/jCacheNamespaceDriven-resolver.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java index 0826f00236..97cfff7acb 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java @@ -42,7 +42,7 @@ public interface CachingConfigurer { /** * Return the cache manager bean to use for annotation-driven cache * management. A default {@link CacheResolver} will be initialized - * behind the scene with this cache manager. For more fine-grained + * behind the scenes with this cache manager. For more fine-grained * management of the cache resolution, consider setting the * {@link CacheResolver} directly. *

Implementations must explicitly declare @@ -65,8 +65,10 @@ public interface CachingConfigurer { /** * Return the {@link CacheResolver} bean to use to resolve regular caches for - * annotation-driven cache management. This is an alternative option to set - * the {@link CacheManager} to use. + * annotation-driven cache management. This is an alternative and more powerful + * option of specifying the {@link CacheManager} to use. + *

If both a {@link #cacheManager()} and {@link #cacheResolver()} are set, the + * cache manager is ignored. *

Implementations must explicitly declare * {@link org.springframework.context.annotation.Bean @Bean}, e.g. *

diff --git a/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java
index 5621d5a635..c3fad09bcf 100644
--- a/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java
+++ b/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java
@@ -98,9 +98,20 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
 		}
 	}
 
-	private static void parseCacheManagerProperty(Element element, BeanDefinition def) {
-		def.getPropertyValues().add("cacheManager",
-				new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
+	/**
+	 * Parse the cache resolution strategy to use. If a 'cache-resolver' attribute
+	 * is set, it is injected. Otherwise the 'cache-manager' is set. If {@code setBoth}
+	 * is {@code true}, both service are actually injected.
+	 */
+	private static void parseCacheResolution(Element element, BeanDefinition def, boolean setBoth) {
+		String name = element.getAttribute("cache-resolver");
+		if (StringUtils.hasText(name)) {
+			def.getPropertyValues().add("cacheResolver", new RuntimeBeanReference(name.trim()));
+		}
+		if (!StringUtils.hasText(name) || setBoth) {
+			def.getPropertyValues().add("cacheManager",
+					new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
+		}
 	}
 
 	private static BeanDefinition parseErrorHandler(Element element, BeanDefinition def) {
@@ -130,7 +141,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
 				RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class);
 				interceptorDef.setSource(eleSource);
 				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-				parseCacheManagerProperty(element, interceptorDef);
+				parseCacheResolution(element, interceptorDef, false);
 				parseErrorHandler(element, interceptorDef);
 				CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef);
 				interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName));
@@ -170,7 +181,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
 				RootBeanDefinition def = new RootBeanDefinition();
 				def.setBeanClassName(CACHE_ASPECT_CLASS_NAME);
 				def.setFactoryMethodName("aspectOf");
-				parseCacheManagerProperty(element, def);
+				parseCacheResolution(element, def, false);
 				CacheNamespaceHandler.parseKeyGenerator(element, def);
 				parserContext.registerBeanComponent(new BeanComponentDefinition(def, CACHE_ASPECT_BEAN_NAME));
 			}
@@ -239,7 +250,9 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
 			RootBeanDefinition sourceDef = new RootBeanDefinition(JCACHE_OPERATION_SOURCE_CLASS);
 			sourceDef.setSource(eleSource);
 			sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-			parseCacheManagerProperty(element, sourceDef);
+			// JSR-107 support should create an exception cache resolver with the cache manager
+			// and there is no way to set that exception cache resolver from the namespace
+			parseCacheResolution(element, sourceDef, true);
 			CacheNamespaceHandler.parseKeyGenerator(element, sourceDef);
 			return sourceDef;
 		}
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleCacheResolver.java b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleCacheResolver.java
index 353de00c6f..7eb01e19bf 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleCacheResolver.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleCacheResolver.java
@@ -32,6 +32,9 @@ import org.springframework.cache.CacheManager;
  */
 public class SimpleCacheResolver extends BaseCacheResolver {
 
+	public SimpleCacheResolver() {
+	}
+
 	public SimpleCacheResolver(CacheManager cacheManager) {
 		super(cacheManager);
 	}
diff --git a/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.1.xsd b/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.1.xsd
index 9c6b547c9e..66104b98db 100644
--- a/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.1.xsd
+++ b/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.1.xsd
@@ -26,7 +26,10 @@
 	annotations on bean classes, and that proxies are automatically
 	to be created for the relevant annotated beans.
 
-	The default annotations supported are Spring's @Cacheable and @CacheEvict.
+	The default annotations supported are Spring's @Cacheable, @CachePut and @CacheEvict. If
+	spring-context-support and the JSR-107 API are on the classpath, additional proxies are
+	automatically created for JSR-107 annotated beans, that is @CacheResult, @CachePut,
+	@CacheRemove and @CacheRemoveAll.
 
 	See org.springframework.cache.annotation.EnableCaching Javadoc
 	for information on code-based alternatives to this XML element.
@@ -35,11 +38,15 @@
 			
 				
 					
 					
 						
@@ -48,6 +55,21 @@
 					
 				
 			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
 			
 				
 					
+
+
+	
+
+	
+		
+			
+				
+			
+		
+	
+
+	
+		
+	
+
diff --git a/spring-context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace-resolver.xml b/spring-context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace-resolver.xml
new file mode 100644
index 0000000000..013111799c
--- /dev/null
+++ b/spring-context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace-resolver.xml
@@ -0,0 +1,22 @@
+
+
+
+	
+
+	
+		
+			
+				
+					
+						
+					
+				
+			
+		
+	
+
diff --git a/src/asciidoc/index.adoc b/src/asciidoc/index.adoc
index d33faa527c..8727790c23 100644
--- a/src/asciidoc/index.adoc
+++ b/src/asciidoc/index.adoc
@@ -47193,8 +47193,17 @@ application through AOP. The configuration is intentionally similar with that of
 | `cache-manager`
 | N/A (See `CachingConfigurer` javadocs)
 | cacheManager
-| Name of cache manager to use. Only required if the name of the cache manager is not
-  `cacheManager`.
+| Name of cache manager to use. A default `CacheResolver` will be initialized behind
+  the scenes with this cache manager (or `cacheManager`if not set). For more
+  fine-grained management of the cache resolution, consider setting the 'cache-resolver'
+  attribute.
+
+| `cache-resolver`
+| N/A (See `CachingConfigurer` javadocs)
+| A `SimpleCacheResolver` using the configured `cacheManager`.
+| The bean name of the CacheResolver that is to be used to resolve the backing caches.
+  This attribute is not required, and only needs to be specified as an alternative to
+  the 'cache-manager' attribute.
 
 | `key-generator`
 | N/A (See `CachingConfigurer` javadocs)