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:
@@ -26,15 +26,19 @@ import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.cache.config.SomeKeyGenerator;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.NamedCacheResolver;
|
||||
import org.springframework.cache.interceptor.SimpleCacheResolver;
|
||||
import org.springframework.cache.interceptor.SimpleKeyGenerator;
|
||||
import org.springframework.cache.jcache.interceptor.AnnotatedJCacheableService;
|
||||
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
|
||||
import org.springframework.cache.jcache.interceptor.SimpleExceptionCacheResolver;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -61,6 +65,35 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
cos.getDefaultExceptionCacheResolver());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyConfigSupport() {
|
||||
ConfigurableApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(EmptyConfigSupportConfig.class);
|
||||
|
||||
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
|
||||
assertNotNull(cos.getDefaultCacheResolver());
|
||||
assertEquals(SimpleCacheResolver.class, cos.getDefaultCacheResolver().getClass());
|
||||
assertSame(context.getBean(CacheManager.class),
|
||||
((SimpleCacheResolver) cos.getDefaultCacheResolver()).getCacheManager());
|
||||
assertNotNull(cos.getDefaultExceptionCacheResolver());
|
||||
assertEquals(SimpleExceptionCacheResolver.class, cos.getDefaultExceptionCacheResolver().getClass());
|
||||
assertSame(context.getBean(CacheManager.class),
|
||||
((SimpleExceptionCacheResolver) cos.getDefaultExceptionCacheResolver()).getCacheManager());
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bothSetOnlyResolverIsUsed() {
|
||||
ConfigurableApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(FullCachingConfigSupport.class);
|
||||
|
||||
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
|
||||
assertSame(context.getBean("cacheResolver"), cos.getDefaultCacheResolver());
|
||||
assertSame(context.getBean("keyGenerator"), cos.getDefaultKeyGenerator());
|
||||
assertSame(context.getBean("exceptionCacheResolver"), cos.getDefaultExceptionCacheResolver());
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@@ -118,4 +151,42 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class EmptyConfigSupportConfig extends JCacheConfigurerSupport {
|
||||
@Bean
|
||||
public CacheManager cm() {
|
||||
return new NoOpCacheManager();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class FullCachingConfigSupport extends JCacheConfigurerSupport {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
return new NoOpCacheManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public KeyGenerator keyGenerator() {
|
||||
return new SomeKeyGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public CacheResolver cacheResolver() {
|
||||
return new NamedCacheResolver(cacheManager(), "foo");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public CacheResolver exceptionCacheResolver() {
|
||||
return new NamedCacheResolver(cacheManager(), "exception");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,18 +19,14 @@ package org.springframework.cache.jcache.interceptor;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
|
||||
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.NamedCacheResolver;
|
||||
import org.springframework.cache.jcache.AbstractJCacheTests;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -45,7 +41,7 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||
@Test
|
||||
public void severalCachesNotSupported() {
|
||||
JCacheInterceptor interceptor = createInterceptor(createOperationSource(
|
||||
cacheManager, new TestCacheResolver("default", "exception"),
|
||||
cacheManager, new NamedCacheResolver(cacheManager, "default", "simpleCache"),
|
||||
defaultExceptionCacheResolver, defaultKeyGenerator));
|
||||
|
||||
AnnotatedJCacheableService service = new AnnotatedJCacheableService(cacheManager.getCache("default"));
|
||||
@@ -65,7 +61,7 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||
@Test
|
||||
public void noCacheCouldBeResolved() {
|
||||
JCacheInterceptor interceptor = createInterceptor(createOperationSource(
|
||||
cacheManager, new TestCacheResolver(), // Returns empty list
|
||||
cacheManager, new NamedCacheResolver(cacheManager), // Returns empty list
|
||||
defaultExceptionCacheResolver, defaultKeyGenerator));
|
||||
|
||||
AnnotatedJCacheableService service = new AnnotatedJCacheableService(cacheManager.getCache("default"));
|
||||
@@ -132,25 +128,6 @@ public class JCacheInterceptorTests extends AbstractJCacheTests {
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
|
||||
private class TestCacheResolver implements CacheResolver {
|
||||
|
||||
private final String[] cacheNames;
|
||||
|
||||
private TestCacheResolver(String... cacheNames) {
|
||||
this.cacheNames = cacheNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
|
||||
List<Cache> result = new ArrayList<Cache>();
|
||||
for (String cacheName : cacheNames) {
|
||||
result.add(cacheManager.getCache(cacheName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyInvoker implements CacheOperationInvoker {
|
||||
|
||||
private final Object result;
|
||||
|
||||
Reference in New Issue
Block a user