Use CacheResolver in Spring abstraction

Prior to this commit, the CacheResolver was not used by Spring's
caching abstraction. This commit provides the necessary configuration
options to tune how a cache is resolved for a given operation.

CacheResolver can be customized globally, at the operation level or at
the class level. This breaks the CachingConfigurer class and a support
implementation is provided that implements all methods so that the
default is taken if it's not overridden. The JSR-107 support has been
updated as well, with a similar support class.

In particular, the static and runtime information of a cache
operation were mixed which prevents any forms of caching. As the
CacheResolver and the KeyGenerator can be customized, every operation
call lead to a lookup in the context for the bean.

This commit adds CacheOperationMetadata, a static holder of all
the non-runtime metadata about a cache operation. This is used
as an input source for the existing CacheOperationContext.

Caching the operation metadata in an AspectJ aspect can have side
effects as the aspect is static instance for the current ClassLoader.
The metadata cache needs to be cleared when the context shutdowns.
This is essentially a test issue only as in practice each application
runs in its class loader. Tests are now closing the context properly
to honor the DisposableBean callback.

Issue: SPR-11490
This commit is contained in:
Stephane Nicoll
2014-02-27 15:21:07 +01:00
parent 47a4327193
commit f3b8a4103e
32 changed files with 1333 additions and 245 deletions

View File

@@ -36,13 +36,11 @@ import org.springframework.context.annotation.Role;
@Configuration
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration<JCacheConfigurer> {
protected CacheResolver cacheResolver;
protected CacheResolver exceptionCacheResolver;
@Override
protected void useCachingConfigurer(JCacheConfigurer config) {
super.useCachingConfigurer(config);
this.cacheResolver = config.cacheResolver();
this.exceptionCacheResolver = config.exceptionCacheResolver();
}

View File

@@ -21,42 +21,25 @@ import org.springframework.cache.interceptor.CacheResolver;
/**
* Extension of {@link CachingConfigurer} for the JSR-107 implementation.
* <p>To be implemented by classes annotated with @{@link org.springframework.cache.annotation.EnableCaching}
* that wish or need to specify explicitly the {@link CacheResolver} bean(s) to be used for
* annotation-driven cache management.
*
* <p>See @{@link org.springframework.cache.annotation.EnableCaching} for general examples and
* context; see {@link #cacheResolver()} and {@link #exceptionCacheResolver()} for detailed
* <p>To be implemented by classes annotated with
* @{@link org.springframework.cache.annotation.EnableCaching} that wish or
* need to specify explicitly how exception caches are resolved for
* annotation-driven cache management. Consider extending {@link JCacheConfigurerSupport},
* which provides a stub implementation of all interface methods.
*
* <p>See @{@link org.springframework.cache.annotation.EnableCaching} for
* general examples and context; see {@link #exceptionCacheResolver()} for detailed
* instructions.
*
* @author Stephane Nicoll
* @since 4.1
* @see CachingConfigurer
* @see JCacheConfigurerSupport
* @see org.springframework.cache.annotation.EnableCaching
*/
public interface JCacheConfigurer extends CachingConfigurer {
/**
* Return the {@link CacheResolver} bean to use to resolve regular caches for
* annotation-driven cache management. Implementations must explicitly declare
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
* <pre class="code">
* &#064;Configuration
* &#064;EnableCaching
* public class AppConfig implements JCacheConfigurer {
* &#064;Bean // important!
* &#064;Override
* public CacheResolver cacheResolver() {
* // configure and return CacheResolver instance
* }
* // ...
* }
* </pre>
* See {@link org.springframework.cache.annotation.EnableCaching} for more complete examples.
*/
CacheResolver cacheResolver();
/**
* Return the {@link CacheResolver} bean to use to resolve exception caches for
* annotation-driven cache management. Implementations must explicitly declare
@@ -64,7 +47,7 @@ public interface JCacheConfigurer extends CachingConfigurer {
* <pre class="code">
* &#064;Configuration
* &#064;EnableCaching
* public class AppConfig implements JCacheConfigurer {
* public class AppConfig extends JCacheConfigurerSupport {
* &#064;Bean // important!
* &#064;Override
* public CacheResolver exceptionCacheResolver() {

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2014 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.jcache.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.CacheResolver;
/**
* An extension of {@link CachingConfigurerSupport} that also implements
* {@link JCacheConfigurer}.
*
* <p>Users of JSR-107 annotations may extend from this class rather than
* implementing from {@link JCacheConfigurer} directly.
*
* @author Stephane Nicoll
* @since 4.1
* @see JCacheConfigurer
* @see CachingConfigurerSupport
*/
public class JCacheConfigurerSupport extends CachingConfigurerSupport implements JCacheConfigurer {
@Override
public CacheResolver exceptionCacheResolver() {
return null;
}
}

View File

@@ -19,13 +19,12 @@ package org.springframework.cache.jcache.interceptor;
import java.util.Collection;
import java.util.Collections;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.BaseCacheResolver;
import org.springframework.cache.interceptor.BasicCacheOperation;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.jcache.model.CacheResultOperation;
import org.springframework.util.Assert;
/**
* A simple {@link CacheResolver} that resolves the exception cache
@@ -36,16 +35,14 @@ import org.springframework.util.Assert;
* @since 4.1
* @see org.springframework.cache.jcache.model.CacheResultOperation#getExceptionCacheName()
*/
public class SimpleExceptionCacheResolver implements CacheResolver {
private final CacheManager cacheManager;
public class SimpleExceptionCacheResolver extends BaseCacheResolver {
public SimpleExceptionCacheResolver(CacheManager cacheManager) {
this.cacheManager = cacheManager;
super(cacheManager);
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
BasicCacheOperation operation = context.getOperation();
if (!(operation instanceof CacheResultOperation)) {
throw new IllegalStateException("Could not extract exception cache name from " + operation);
@@ -53,9 +50,7 @@ public class SimpleExceptionCacheResolver implements CacheResolver {
CacheResultOperation cacheResultOperation = (CacheResultOperation) operation;
String exceptionCacheName = cacheResultOperation.getExceptionCacheName();
if (exceptionCacheName != null) {
Cache cache = cacheManager.getCache(exceptionCacheName);
Assert.notNull(cache, "Cannot find cache named '" + exceptionCacheName + "' for " + operation);
return Collections.singleton(cache);
return Collections.singleton(exceptionCacheName);
}
return null;
}