Skip to content

Commit 0e36402

Browse files
committed
Revised retrieval of cache strategy beans
Issue: SPR-12336
1 parent cfa3d35 commit 0e36402

File tree

7 files changed

+210
-176
lines changed

7 files changed

+210
-176
lines changed

spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractCacheInterceptor.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.cache.interceptor.CacheErrorHandler;
2929
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
3030
import org.springframework.cache.interceptor.CacheOperationInvoker;
31+
import org.springframework.util.CollectionUtils;
3132

3233
/**
3334
* A base interceptor for JSR-107 cache annotations.
@@ -41,12 +42,15 @@ abstract class AbstractCacheInterceptor<O extends AbstractJCacheOperation<A>, A
4142

4243
protected final Log logger = LogFactory.getLog(getClass());
4344

45+
4446
protected AbstractCacheInterceptor(CacheErrorHandler errorHandler) {
4547
super(errorHandler);
4648
}
4749

48-
protected abstract Object invoke(CacheOperationInvocationContext<O> context,
49-
CacheOperationInvoker invoker) throws Throwable;
50+
51+
protected abstract Object invoke(CacheOperationInvocationContext<O> context, CacheOperationInvoker invoker)
52+
throws Throwable;
53+
5054

5155
/**
5256
* Resolve the cache to use.
@@ -68,15 +72,15 @@ protected Cache resolveCache(CacheOperationInvocationContext<O> context) {
6872
* @return the singe element or {@code null} if the collection is empty
6973
*/
7074
static Cache extractFrom(Collection<? extends Cache> caches) {
71-
if (caches == null || caches.size() == 0) {
75+
if (CollectionUtils.isEmpty(caches)) {
7276
return null;
7377
}
7478
else if (caches.size() == 1) {
7579
return caches.iterator().next();
7680
}
7781
else {
78-
throw new IllegalStateException("Unsupported cache resolution result "
79-
+ caches + " JSR-107 only supports a single cache.");
82+
throw new IllegalStateException("Unsupported cache resolution result " + caches +
83+
": JSR-107 only supports a single cache.");
8084
}
8185
}
8286

spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AnnotationJCacheOperationSource.java

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,44 +43,22 @@
4343
*/
4444
public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJCacheOperationSource {
4545

46-
/**
47-
* Locate or create an instance of the specified {@code type}.
48-
* @param type the type of the bean to manage
49-
* @return the required bean
50-
*/
51-
protected abstract <T> T getBean(Class<T> type);
52-
53-
/**
54-
* Return the default {@link CacheResolver} if none is set.
55-
*/
56-
protected abstract CacheResolver getDefaultCacheResolver();
57-
58-
/**
59-
* Return the default exception {@link CacheResolver} if none is set.
60-
*/
61-
protected abstract CacheResolver getDefaultExceptionCacheResolver();
62-
63-
/**
64-
* Return the default {@link KeyGenerator} if none is set.
65-
*/
66-
protected abstract KeyGenerator getDefaultKeyGenerator();
67-
68-
6946
@Override
7047
protected JCacheOperation<?> findCacheOperation(Method method, Class<?> targetType) {
7148
CacheResult cacheResult = method.getAnnotation(CacheResult.class);
7249
CachePut cachePut = method.getAnnotation(CachePut.class);
7350
CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
7451
CacheRemoveAll cacheRemoveAll = method.getAnnotation(CacheRemoveAll.class);
52+
7553
int found = countNonNull(cacheResult, cachePut, cacheRemove, cacheRemoveAll);
7654
if (found == 0) {
7755
return null;
7856
}
7957
if (found > 1) {
8058
throw new IllegalStateException("More than one cache annotation found on '" + method + "'");
8159
}
82-
CacheDefaults defaults = getCacheDefaults(method, targetType);
8360

61+
CacheDefaults defaults = getCacheDefaults(method, targetType);
8462
if (cacheResult != null) {
8563
return createCacheResultOperation(method, defaults, cacheResult);
8664
}
@@ -103,9 +81,7 @@ protected CacheDefaults getCacheDefaults(Method method, Class<?> targetType) {
10381
return targetType.getAnnotation(CacheDefaults.class);
10482
}
10583

106-
107-
protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults,
108-
CacheResult ann) {
84+
protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults, CacheResult ann) {
10985
String cacheName = determineCacheName(method, defaults, ann.cacheName());
11086
CacheResolverFactory cacheResolverFactory =
11187
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
@@ -123,49 +99,39 @@ protected CacheResultOperation createCacheResultOperation(Method method, CacheDe
12399
return new CacheResultOperation(methodDetails, cacheResolver, keyGenerator, exceptionCacheResolver);
124100
}
125101

126-
protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults,
127-
CachePut ann) {
102+
protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults, CachePut ann) {
128103
String cacheName = determineCacheName(method, defaults, ann.cacheName());
129104
CacheResolverFactory cacheResolverFactory =
130105
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
131106
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
132107

133108
CacheMethodDetails<CachePut> methodDetails = createMethodDetails(method, ann, cacheName);
134-
135109
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
136-
137110
return new CachePutOperation(methodDetails, cacheResolver, keyGenerator);
138111
}
139112

140-
protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults,
141-
CacheRemove ann) {
113+
protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults, CacheRemove ann) {
142114
String cacheName = determineCacheName(method, defaults, ann.cacheName());
143115
CacheResolverFactory cacheResolverFactory =
144116
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
145117
KeyGenerator keyGenerator = determineKeyGenerator(defaults, ann.cacheKeyGenerator());
146118

147119
CacheMethodDetails<CacheRemove> methodDetails = createMethodDetails(method, ann, cacheName);
148-
149120
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
150-
151121
return new CacheRemoveOperation(methodDetails, cacheResolver, keyGenerator);
152122
}
153123

154-
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults,
155-
CacheRemoveAll ann) {
124+
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults, CacheRemoveAll ann) {
156125
String cacheName = determineCacheName(method, defaults, ann.cacheName());
157126
CacheResolverFactory cacheResolverFactory =
158127
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
159128

160129
CacheMethodDetails<CacheRemoveAll> methodDetails = createMethodDetails(method, ann, cacheName);
161-
162130
CacheResolver cacheResolver = getCacheResolver(cacheResolverFactory, methodDetails);
163-
164131
return new CacheRemoveAllOperation(methodDetails, cacheResolver);
165132
}
166133

167-
private <A extends Annotation> CacheMethodDetails<A> createMethodDetails(
168-
Method method, A annotation, String cacheName) {
134+
private <A extends Annotation> CacheMethodDetails<A> createMethodDetails(Method method, A annotation, String cacheName) {
169135
return new DefaultCacheMethodDetails<A>(method, annotation, cacheName);
170136
}
171137

@@ -181,6 +147,7 @@ protected CacheResolver getCacheResolver(CacheResolverFactory factory, CacheMeth
181147

182148
protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory,
183149
CacheMethodDetails<CacheResult> details) {
150+
184151
if (factory != null) {
185152
javax.cache.annotation.CacheResolver cacheResolver = factory.getExceptionCacheResolver(details);
186153
return new CacheResolverAdapter(cacheResolver);
@@ -192,6 +159,7 @@ protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory,
192159

193160
protected CacheResolverFactory determineCacheResolverFactory(CacheDefaults defaults,
194161
Class<? extends CacheResolverFactory> candidate) {
162+
195163
if (!CacheResolverFactory.class.equals(candidate)) {
196164
return getBean(candidate);
197165
}
@@ -203,8 +171,7 @@ else if (defaults != null && !CacheResolverFactory.class.equals(defaults.cacheRe
203171
}
204172
}
205173

206-
protected KeyGenerator determineKeyGenerator(CacheDefaults defaults,
207-
Class<? extends CacheKeyGenerator> candidate) {
174+
protected KeyGenerator determineKeyGenerator(CacheDefaults defaults, Class<? extends CacheKeyGenerator> candidate) {
208175
if (!CacheKeyGenerator.class.equals(candidate)) {
209176
return new KeyGeneratorAdapter(this, getBean(candidate));
210177
}
@@ -233,28 +200,48 @@ protected String determineCacheName(Method method, CacheDefaults defaults, Strin
233200
*/
234201
protected String generateDefaultCacheName(Method method) {
235202
Class<?>[] parameterTypes = method.getParameterTypes();
236-
List<String> parameters = new ArrayList<String>();
203+
List<String> parameters = new ArrayList<String>(parameterTypes.length);
237204
for (Class<?> parameterType : parameterTypes) {
238205
parameters.add(parameterType.getName());
239206
}
240207

241-
StringBuilder sb = new StringBuilder();
242-
sb.append(method.getDeclaringClass().getName())
243-
.append(".")
244-
.append(method.getName())
245-
.append("(")
246-
.append(StringUtils.collectionToCommaDelimitedString(parameters))
247-
.append(")");
208+
StringBuilder sb = new StringBuilder(method.getDeclaringClass().getName());
209+
sb.append(".").append(method.getName());
210+
sb.append("(").append(StringUtils.collectionToCommaDelimitedString(parameters)).append(")");
248211
return sb.toString();
249212
}
250213

251214
private int countNonNull(Object... instances) {
252215
int result = 0;
253-
for (Object o : instances) {
254-
if (o != null) {
216+
for (Object instance : instances) {
217+
if (instance != null) {
255218
result += 1;
256219
}
257220
}
258221
return result;
259222
}
223+
224+
225+
/**
226+
* Locate or create an instance of the specified cache strategy {@code type}.
227+
* @param type the type of the bean to manage
228+
* @return the required bean
229+
*/
230+
protected abstract <T> T getBean(Class<T> type);
231+
232+
/**
233+
* Return the default {@link CacheResolver} if none is set.
234+
*/
235+
protected abstract CacheResolver getDefaultCacheResolver();
236+
237+
/**
238+
* Return the default exception {@link CacheResolver} if none is set.
239+
*/
240+
protected abstract CacheResolver getDefaultExceptionCacheResolver();
241+
242+
/**
243+
* Return the default {@link KeyGenerator} if none is set.
244+
*/
245+
protected abstract KeyGenerator getDefaultKeyGenerator();
246+
260247
}

spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
package org.springframework.cache.jcache.interceptor;
1818

19-
import java.util.Map;
20-
2119
import org.springframework.beans.BeanUtils;
22-
import org.springframework.beans.factory.BeanFactoryUtils;
2320
import org.springframework.beans.factory.InitializingBean;
21+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
22+
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
2423
import org.springframework.beans.factory.SmartInitializingSingleton;
2524
import org.springframework.cache.CacheManager;
2625
import org.springframework.cache.interceptor.CacheResolver;
@@ -40,7 +39,7 @@
4039
* @since 4.1
4140
*/
4241
public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource
43-
implements InitializingBean, SmartInitializingSingleton, ApplicationContextAware {
42+
implements ApplicationContextAware, InitializingBean, SmartInitializingSingleton {
4443

4544
private CacheManager cacheManager;
4645

@@ -54,6 +53,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
5453

5554
private ApplicationContext applicationContext;
5655

56+
5757
/**
5858
* Set the default {@link CacheManager} to use to lookup cache by name. Only mandatory
5959
* if the {@linkplain CacheResolver cache resolvers} have not been set.
@@ -104,24 +104,33 @@ public void setApplicationContext(ApplicationContext applicationContext) {
104104
this.applicationContext = applicationContext;
105105
}
106106

107+
107108
@Override
108109
public void afterPropertiesSet() {
109110
this.adaptedKeyGenerator = new KeyGeneratorAdapter(this, this.keyGenerator);
110111
}
111112

112113
@Override
113-
public void afterSingletonsInstantiated() { // Make sure those are initialized on startup
114-
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized.");
115-
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized.");
114+
public void afterSingletonsInstantiated() {
115+
// Make sure those are initialized on startup...
116+
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
117+
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized");
116118
}
117119

120+
118121
@Override
119122
protected <T> T getBean(Class<T> type) {
120-
Map<String, T> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, type);
121-
if (map.size() == 1) {
122-
return map.values().iterator().next();
123+
try {
124+
return this.applicationContext.getBean(type);
123125
}
124-
else {
126+
catch (NoUniqueBeanDefinitionException ex) {
127+
throw new IllegalStateException("No unique [" + type.getName() + "] bean found in application context - " +
128+
"mark one as primary, or declare a more specific implementation type for your cache", ex);
129+
}
130+
catch (NoSuchBeanDefinitionException ex) {
131+
if (logger.isDebugEnabled()) {
132+
logger.debug("No bean of type [" + type.getName() + "] found in application context", ex);
133+
}
125134
return BeanUtils.instantiateClass(type);
126135
}
127136
}
@@ -149,11 +158,16 @@ protected KeyGenerator getDefaultKeyGenerator() {
149158

150159
private CacheManager getCacheManager() {
151160
if (this.cacheManager == null) {
152-
this.cacheManager = this.applicationContext.getBean(CacheManager.class);
153-
if (this.cacheManager == null) {
154-
throw new IllegalStateException("No bean of type CacheManager could be found. " +
155-
"Register a CacheManager bean or remove the @EnableCaching annotation " +
156-
"from your configuration.");
161+
try {
162+
this.cacheManager = this.applicationContext.getBean(CacheManager.class);
163+
}
164+
catch (NoUniqueBeanDefinitionException ex) {
165+
throw new IllegalStateException("No unique bean of type CacheManager found. "+
166+
"Mark one as primary or declare a specific CacheManager to use.");
167+
}
168+
catch (NoSuchBeanDefinitionException ex) {
169+
throw new IllegalStateException("No bean of type CacheManager found. Register a CacheManager "+
170+
"bean or remove the @EnableCaching annotation from your configuration.");
157171
}
158172
}
159173
return this.cacheManager;

spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheAspectSupport.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ public JCacheOperationSource getCacheOperationSource() {
7878
}
7979

8080
public void afterPropertiesSet() {
81-
Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSource' property is required: " +
81+
Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSource' property is required: " +
8282
"If there are no cacheable methods, then don't use a cache aspect.");
83-
Assert.state(this.getErrorHandler() != null, "The 'errorHandler' is required.");
83+
Assert.state(getErrorHandler() != null, "The 'errorHandler' is required");
8484

8585
this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler());
8686
this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler());
@@ -92,8 +92,7 @@ public void afterPropertiesSet() {
9292

9393

9494
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
95-
// check whether aspect is enabled
96-
// to cope with cases where the AJ is pulled in automatically
95+
// Check whether aspect is enabled to cope with cases where the AJ is pulled in automatically
9796
if (this.initialized) {
9897
Class<?> targetClass = getTargetClass(target);
9998
JCacheOperation<?> operation = getCacheOperationSource().getCacheOperation(method, targetClass);
@@ -108,9 +107,9 @@ protected Object execute(CacheOperationInvoker invoker, Object target, Method me
108107
}
109108

110109
@SuppressWarnings("unchecked")
111-
private CacheOperationInvocationContext<?> createCacheOperationInvocationContext(Object target,
112-
Object[] args,
113-
JCacheOperation<?> operation) {
110+
private CacheOperationInvocationContext<?> createCacheOperationInvocationContext(
111+
Object target, Object[] args, JCacheOperation<?> operation) {
112+
114113
return new DefaultCacheInvocationContext<Annotation>(
115114
(JCacheOperation<Annotation>) operation, target, args);
116115
}
@@ -124,12 +123,10 @@ private Class<?> getTargetClass(Object target) {
124123
}
125124

126125
@SuppressWarnings("unchecked")
127-
private Object execute(CacheOperationInvocationContext<?> context,
128-
CacheOperationInvoker invoker) {
129-
126+
private Object execute(CacheOperationInvocationContext<?> context, CacheOperationInvoker invoker) {
130127
CacheOperationInvoker adapter = new CacheOperationInvokerAdapter(invoker);
131-
132128
BasicOperation operation = context.getOperation();
129+
133130
if (operation instanceof CacheResultOperation) {
134131
return cacheResultInterceptor.invoke(
135132
(CacheOperationInvocationContext<CacheResultOperation>) context, adapter);

0 commit comments

Comments
 (0)