Lazily retrieve delegate beans in AsyncConfigurer and CachingConfigurer

Introduces a configure method pattern for Supplier-style configuration and a common SingletonSupplier decorator for method reference suppliers. Also declares jcache.config and jcache.interceptor for non-null conventions.

Issue: SPR-17021
This commit is contained in:
Juergen Hoeller
2018-07-14 19:29:32 +02:00
parent 680afa75d8
commit f6fdffd663
53 changed files with 785 additions and 330 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -16,6 +16,8 @@
package org.springframework.cache.jcache.config;
import java.util.function.Supplier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.annotation.AbstractCachingConfiguration;
import org.springframework.cache.annotation.CachingConfigurer;
@@ -25,45 +27,37 @@ import org.springframework.cache.jcache.interceptor.JCacheOperationSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.lang.Nullable;
/**
* Abstract JSR-107 specific {@code @Configuration} class providing common
* structure for enabling JSR-107 annotation-driven cache management capability.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see JCacheConfigurer
*/
@Configuration
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration {
protected CacheResolver exceptionCacheResolver;
@Nullable
protected Supplier<CacheResolver> exceptionCacheResolver;
@Override
protected void useCachingConfigurer(CachingConfigurer config) {
super.useCachingConfigurer(config);
if (config instanceof JCacheConfigurer) {
this.exceptionCacheResolver = ((JCacheConfigurer) config).exceptionCacheResolver();
this.exceptionCacheResolver = ((JCacheConfigurer) config)::exceptionCacheResolver;
}
}
@Bean(name = "jCacheOperationSource")
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JCacheOperationSource cacheOperationSource() {
DefaultJCacheOperationSource source = new DefaultJCacheOperationSource();
if (this.cacheManager != null) {
source.setCacheManager(this.cacheManager);
}
if (this.keyGenerator != null) {
source.setKeyGenerator(this.keyGenerator);
}
if (this.cacheResolver != null) {
source.setCacheResolver(this.cacheResolver);
}
if (this.exceptionCacheResolver != null) {
source.setExceptionCacheResolver(this.exceptionCacheResolver);
}
return source;
return new DefaultJCacheOperationSource(
this.cacheManager, this.cacheResolver, this.exceptionCacheResolver, this.keyGenerator);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.lang.Nullable;
/**
* Extension of {@link CachingConfigurer} for the JSR-107 implementation.
@@ -58,6 +59,7 @@ public interface JCacheConfigurer extends CachingConfigurer {
* </pre>
* See {@link org.springframework.cache.annotation.EnableCaching} for more complete examples.
*/
@Nullable
CacheResolver exceptionCacheResolver();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.lang.Nullable;
/**
* An extension of {@link CachingConfigurerSupport} that also implements
@@ -34,6 +35,7 @@ import org.springframework.cache.interceptor.CacheResolver;
public class JCacheConfigurerSupport extends CachingConfigurerSupport implements JCacheConfigurer {
@Override
@Nullable
public CacheResolver exceptionCacheResolver() {
return null;
}

View File

@@ -31,6 +31,7 @@ import org.springframework.context.annotation.Role;
* <p>Can safely be used alongside Spring's caching support.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see org.springframework.cache.annotation.EnableCaching
* @see org.springframework.cache.annotation.CachingConfigurationSelector
@@ -55,11 +56,8 @@ public class ProxyJCacheConfiguration extends AbstractJCacheConfiguration {
@Bean(name = "jCacheInterceptor")
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JCacheInterceptor cacheInterceptor() {
JCacheInterceptor interceptor = new JCacheInterceptor();
JCacheInterceptor interceptor = new JCacheInterceptor(this.errorHandler);
interceptor.setCacheOperationSource(cacheOperationSource());
if (this.errorHandler != null) {
interceptor.setErrorHandler(this.errorHandler);
}
return interceptor;
}

View File

@@ -6,4 +6,9 @@
* <p>Provide an extension of the {@code CachingConfigurer} that exposes
* the exception cache resolver to use, see {@code JCacheConfigurer}.
*/
@NonNullApi
@NonNullFields
package org.springframework.cache.jcache.config;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -51,6 +51,7 @@ abstract class AbstractCacheInterceptor<O extends AbstractJCacheOperation<A>, A
}
@Nullable
protected abstract Object invoke(CacheOperationInvocationContext<O> context, CacheOperationInvoker invoker)
throws Throwable;

View File

@@ -55,7 +55,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe
@Override
public JCacheOperation<?> getCacheOperation(Method method, Class<?> targetClass) {
public JCacheOperation<?> getCacheOperation(Method method, @Nullable Class<?> targetClass) {
MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
Object cached = this.cache.get(cacheKey);
@@ -78,7 +78,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe
}
@Nullable
private JCacheOperation<?> computeCacheOperation(Method method, Class<?> targetClass) {
private JCacheOperation<?> computeCacheOperation(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
@@ -113,7 +113,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe
* (or {@code null} if none)
*/
@Nullable
protected abstract JCacheOperation<?> findCacheOperation(Method method, Class<?> targetType);
protected abstract JCacheOperation<?> findCacheOperation(Method method, @Nullable Class<?> targetType);
/**
* Should only public methods be allowed to have caching semantics?

View File

@@ -50,7 +50,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
/**
* Create a new instance.
* Construct a new {@code AbstractJCacheOperation}.
* @param methodDetails the {@link CacheMethodDetails} related to the cached method
* @param cacheResolver the cache resolver to resolve regular caches
*/

View File

@@ -39,6 +39,7 @@ abstract class AbstractKeyCacheInterceptor<O extends AbstractJCacheKeyOperation<
super(errorHandler);
}
/**
* Generate a key for the specified invocation.
* @param context the context of the invocation
@@ -58,8 +59,7 @@ abstract class AbstractKeyCacheInterceptor<O extends AbstractJCacheKeyOperation<
* @param context the context of the invocation.
* @return the related {@code CacheKeyInvocationContext}
*/
protected CacheKeyInvocationContext<A> createCacheKeyInvocationContext(
CacheOperationInvocationContext<O> context) {
protected CacheKeyInvocationContext<A> createCacheKeyInvocationContext(CacheOperationInvocationContext<O> context) {
return new DefaultCacheKeyInvocationContext<>(context.getOperation(), context.getTarget(), context.getArgs());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -45,7 +45,7 @@ import org.springframework.util.StringUtils;
public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJCacheOperationSource {
@Override
protected JCacheOperation<?> findCacheOperation(Method method, Class<?> targetType) {
protected JCacheOperation<?> findCacheOperation(Method method, @Nullable Class<?> targetType) {
CacheResult cacheResult = method.getAnnotation(CacheResult.class);
CachePut cachePut = method.getAnnotation(CachePut.class);
CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);
@@ -74,15 +74,16 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
}
}
protected CacheDefaults getCacheDefaults(Method method, Class<?> targetType) {
@Nullable
protected CacheDefaults getCacheDefaults(Method method, @Nullable Class<?> targetType) {
CacheDefaults annotation = method.getDeclaringClass().getAnnotation(CacheDefaults.class);
if (annotation != null) {
return annotation;
}
return targetType.getAnnotation(CacheDefaults.class);
return (targetType != null ? targetType.getAnnotation(CacheDefaults.class) : null);
}
protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults, CacheResult ann) {
protected CacheResultOperation createCacheResultOperation(Method method, @Nullable CacheDefaults defaults, CacheResult ann) {
String cacheName = determineCacheName(method, defaults, ann.cacheName());
CacheResolverFactory cacheResolverFactory =
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
@@ -100,7 +101,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
return new CacheResultOperation(methodDetails, cacheResolver, keyGenerator, exceptionCacheResolver);
}
protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults, CachePut ann) {
protected CachePutOperation createCachePutOperation(Method method, @Nullable CacheDefaults defaults, CachePut ann) {
String cacheName = determineCacheName(method, defaults, ann.cacheName());
CacheResolverFactory cacheResolverFactory =
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
@@ -111,7 +112,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
return new CachePutOperation(methodDetails, cacheResolver, keyGenerator);
}
protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults, CacheRemove ann) {
protected CacheRemoveOperation createCacheRemoveOperation(Method method, @Nullable CacheDefaults defaults, CacheRemove ann) {
String cacheName = determineCacheName(method, defaults, ann.cacheName());
CacheResolverFactory cacheResolverFactory =
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
@@ -122,7 +123,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
return new CacheRemoveOperation(methodDetails, cacheResolver, keyGenerator);
}
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults, CacheRemoveAll ann) {
protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, @Nullable CacheDefaults defaults, CacheRemoveAll ann) {
String cacheName = determineCacheName(method, defaults, ann.cacheName());
CacheResolverFactory cacheResolverFactory =
determineCacheResolverFactory(defaults, ann.cacheResolverFactory());
@@ -136,7 +137,9 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
return new DefaultCacheMethodDetails<>(method, annotation, cacheName);
}
protected CacheResolver getCacheResolver(CacheResolverFactory factory, CacheMethodDetails<?> details) {
protected CacheResolver getCacheResolver(
@Nullable CacheResolverFactory factory, CacheMethodDetails<?> details) {
if (factory != null) {
javax.cache.annotation.CacheResolver cacheResolver = factory.getCacheResolver(details);
return new CacheResolverAdapter(cacheResolver);
@@ -146,8 +149,8 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
}
}
protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory,
CacheMethodDetails<CacheResult> details) {
protected CacheResolver getExceptionCacheResolver(
@Nullable CacheResolverFactory factory, CacheMethodDetails<CacheResult> details) {
if (factory != null) {
javax.cache.annotation.CacheResolver cacheResolver = factory.getExceptionCacheResolver(details);
@@ -159,13 +162,13 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
}
@Nullable
protected CacheResolverFactory determineCacheResolverFactory(CacheDefaults defaults,
Class<? extends CacheResolverFactory> candidate) {
protected CacheResolverFactory determineCacheResolverFactory(
@Nullable CacheDefaults defaults, Class<? extends CacheResolverFactory> candidate) {
if (CacheResolverFactory.class != candidate) {
if (candidate != CacheResolverFactory.class) {
return getBean(candidate);
}
else if (defaults != null && CacheResolverFactory.class != defaults.cacheResolverFactory()) {
else if (defaults != null && defaults.cacheResolverFactory() != CacheResolverFactory.class) {
return getBean(defaults.cacheResolverFactory());
}
else {
@@ -173,8 +176,10 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
}
}
protected KeyGenerator determineKeyGenerator(CacheDefaults defaults, Class<? extends CacheKeyGenerator> candidate) {
if (CacheKeyGenerator.class != candidate) {
protected KeyGenerator determineKeyGenerator(
@Nullable CacheDefaults defaults, Class<? extends CacheKeyGenerator> candidate) {
if (candidate != CacheKeyGenerator.class) {
return new KeyGeneratorAdapter(this, getBean(candidate));
}
else if (defaults != null && CacheKeyGenerator.class != defaults.cacheKeyGenerator()) {
@@ -185,7 +190,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC
}
}
protected String determineCacheName(Method method, CacheDefaults defaults, String candidate) {
protected String determineCacheName(Method method, @Nullable CacheDefaults defaults, String candidate) {
if (StringUtils.hasText(candidate)) {
return candidate;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.cache.jcache.interceptor;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
import org.springframework.lang.Nullable;
/**
* Advisor driven by a {@link JCacheOperationSource}, used to include a
@@ -30,6 +31,7 @@ import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;
@SuppressWarnings("serial")
public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private JCacheOperationSource cacheOperationSource;
private final JCacheOperationSourcePointcut pointcut = new JCacheOperationSourcePointcut() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -37,16 +37,16 @@ class CachePutInterceptor extends AbstractKeyCacheInterceptor<CachePutOperation,
super(errorHandler);
}
@Override
protected Object invoke(CacheOperationInvocationContext<CachePutOperation> context,
CacheOperationInvoker invoker) {
CacheKeyInvocationContext<CachePut> invocationContext = createCacheKeyInvocationContext(context);
@Override
protected Object invoke(
CacheOperationInvocationContext<CachePutOperation> context, CacheOperationInvoker invoker) {
CachePutOperation operation = context.getOperation();
CacheKeyInvocationContext<CachePut> invocationContext = createCacheKeyInvocationContext(context);
boolean earlyPut = operation.isEarlyPut();
Object value = invocationContext.getValueParameter().getValue();
if (earlyPut) {
cacheValue(context, value);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -24,6 +24,7 @@ import javax.cache.annotation.CachePut;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.lang.Nullable;
import org.springframework.util.ExceptionTypeFilter;
/**
@@ -44,13 +45,17 @@ class CachePutOperation extends AbstractJCacheKeyOperation<CachePut> {
CacheMethodDetails<CachePut> methodDetails, CacheResolver cacheResolver, KeyGenerator keyGenerator) {
super(methodDetails, cacheResolver, keyGenerator);
CachePut ann = methodDetails.getCacheAnnotation();
this.exceptionTypeFilter = createExceptionTypeFilter(ann.cacheFor(), ann.noCacheFor());
this.valueParameterDetail = initializeValueParameterDetail(methodDetails.getMethod(), this.allParameterDetails);
if (this.valueParameterDetail == null) {
CacheParameterDetail valueParameterDetail =
initializeValueParameterDetail(methodDetails.getMethod(), this.allParameterDetails);
if (valueParameterDetail == null) {
throw new IllegalArgumentException("No parameter annotated with @CacheValue was found for " +
"" + methodDetails.getMethod());
methodDetails.getMethod());
}
this.valueParameterDetail = valueParameterDetail;
}
@@ -85,6 +90,7 @@ class CachePutOperation extends AbstractJCacheKeyOperation<CachePut> {
}
@Nullable
private static CacheParameterDetail initializeValueParameterDetail(
Method method, List<CacheParameterDetail> allParameters) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -30,21 +30,20 @@ import org.springframework.cache.interceptor.CacheOperationInvoker;
* @since 4.1
*/
@SuppressWarnings("serial")
class CacheRemoveAllInterceptor
extends AbstractCacheInterceptor<CacheRemoveAllOperation, CacheRemoveAll> {
class CacheRemoveAllInterceptor extends AbstractCacheInterceptor<CacheRemoveAllOperation, CacheRemoveAll> {
protected CacheRemoveAllInterceptor(CacheErrorHandler errorHandler) {
super(errorHandler);
}
@Override
protected Object invoke(CacheOperationInvocationContext<CacheRemoveAllOperation> context,
CacheOperationInvoker invoker) {
protected Object invoke(
CacheOperationInvocationContext<CacheRemoveAllOperation> context, CacheOperationInvoker invoker) {
CacheRemoveAllOperation operation = context.getOperation();
boolean earlyRemove = operation.isEarlyRemove();
if (earlyRemove) {
removeAll(context);
}

View File

@@ -36,13 +36,14 @@ class CacheRemoveEntryInterceptor extends AbstractKeyCacheInterceptor<CacheRemov
super(errorHandler);
}
@Override
protected Object invoke(CacheOperationInvocationContext<CacheRemoveOperation> context,
CacheOperationInvoker invoker) {
protected Object invoke(
CacheOperationInvocationContext<CacheRemoveOperation> context, CacheOperationInvoker invoker) {
CacheRemoveOperation operation = context.getOperation();
final boolean earlyRemove = operation.isEarlyRemove();
boolean earlyRemove = operation.isEarlyRemove();
if (earlyRemove) {
removeValue(context);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -24,6 +24,7 @@ import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheOperationInvoker;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ExceptionTypeFilter;
import org.springframework.util.SerializationUtils;
@@ -42,8 +43,9 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
@Override
protected Object invoke(CacheOperationInvocationContext<CacheResultOperation> context,
CacheOperationInvoker invoker) {
@Nullable
protected Object invoke(
CacheOperationInvocationContext<CacheResultOperation> context, CacheOperationInvoker invoker) {
CacheResultOperation operation = context.getOperation();
Object cacheKey = generateKey(context);
@@ -74,17 +76,19 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
/**
* Check for a cached exception. If the exception is found, throw it directly.
*/
protected void checkForCachedException(Cache exceptionCache, Object cacheKey) {
protected void checkForCachedException(@Nullable Cache exceptionCache, Object cacheKey) {
if (exceptionCache == null) {
return;
}
Cache.ValueWrapper result = doGet(exceptionCache, cacheKey);
if (result != null) {
throw rewriteCallStack((Throwable) result.get(), getClass().getName(), "invoke");
Throwable ex = (Throwable) result.get();
Assert.state(ex != null, "No exception in cache");
throw rewriteCallStack(ex, getClass().getName(), "invoke");
}
}
protected void cacheException(Cache exceptionCache, ExceptionTypeFilter filter, Object cacheKey, Throwable ex) {
protected void cacheException(@Nullable Cache exceptionCache, ExceptionTypeFilter filter, Object cacheKey, Throwable ex) {
if (exceptionCache == null) {
return;
}
@@ -143,6 +147,7 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
}
@SuppressWarnings("unchecked")
@Nullable
private static <T extends Throwable> T cloneException(T exception) {
try {
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(exception));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -36,15 +36,18 @@ class CacheResultOperation extends AbstractJCacheKeyOperation<CacheResult> {
private final ExceptionTypeFilter exceptionTypeFilter;
@Nullable
private final CacheResolver exceptionCacheResolver;
@Nullable
private final String exceptionCacheName;
public CacheResultOperation(CacheMethodDetails<CacheResult> methodDetails, CacheResolver cacheResolver,
KeyGenerator keyGenerator, CacheResolver exceptionCacheResolver) {
KeyGenerator keyGenerator, @Nullable CacheResolver exceptionCacheResolver) {
super(methodDetails, cacheResolver, keyGenerator);
CacheResult ann = methodDetails.getCacheAnnotation();
this.exceptionTypeFilter = createExceptionTypeFilter(ann.cachedExceptions(), ann.nonCachedExceptions());
this.exceptionCacheResolver = exceptionCacheResolver;
@@ -70,6 +73,7 @@ class CacheResultOperation extends AbstractJCacheKeyOperation<CacheResult> {
* Return the {@link CacheResolver} instance to use to resolve the cache to
* use for matching exceptions thrown by this operation.
*/
@Nullable
public CacheResolver getExceptionCacheResolver() {
return this.exceptionCacheResolver;
}

View File

@@ -20,6 +20,8 @@ import java.lang.annotation.Annotation;
import javax.cache.annotation.CacheInvocationParameter;
import javax.cache.annotation.CacheKeyInvocationContext;
import org.springframework.lang.Nullable;
/**
* The default {@link CacheKeyInvocationContext} implementation.
*
@@ -32,10 +34,11 @@ class DefaultCacheKeyInvocationContext<A extends Annotation>
private final CacheInvocationParameter[] keyParameters;
@Nullable
private final CacheInvocationParameter valueParameter;
public DefaultCacheKeyInvocationContext(AbstractJCacheKeyOperation<A> operation,
Object target, Object[] args) {
public DefaultCacheKeyInvocationContext(AbstractJCacheKeyOperation<A> operation, Object target, Object[] args) {
super(operation, target, args);
this.keyParameters = operation.getKeyParameters(args);
if (operation instanceof CachePutOperation) {
@@ -46,12 +49,14 @@ class DefaultCacheKeyInvocationContext<A extends Annotation>
}
}
@Override
public CacheInvocationParameter[] getKeyParameters() {
return this.keyParameters.clone();
}
@Override
@Nullable
public CacheInvocationParameter getValueParameter() {
return this.valueParameter;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 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.
@@ -17,11 +17,11 @@
package org.springframework.cache.jcache.interceptor;
import java.util.Collection;
import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
@@ -34,6 +34,8 @@ import org.springframework.cache.interceptor.SimpleCacheResolver;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.util.function.SupplierUtils;
/**
* The default {@link JCacheOperationSource} implementation delegating
@@ -41,30 +43,61 @@ import org.springframework.util.Assert;
* when not present.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
*/
public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource
implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
implements BeanFactoryAware, SmartInitializingSingleton {
private CacheManager cacheManager;
@Nullable
private SingletonSupplier<CacheManager> cacheManager;
private CacheResolver cacheResolver;
@Nullable
private SingletonSupplier<CacheResolver> cacheResolver;
private CacheResolver exceptionCacheResolver;
@Nullable
private SingletonSupplier<CacheResolver> exceptionCacheResolver;
private KeyGenerator keyGenerator = new SimpleKeyGenerator();
private SingletonSupplier<KeyGenerator> keyGenerator;
private KeyGenerator adaptedKeyGenerator;
private final SingletonSupplier<KeyGenerator> adaptedKeyGenerator =
SingletonSupplier.of(() -> new KeyGeneratorAdapter(this, getKeyGenerator()));
@Nullable
private BeanFactory beanFactory;
/**
* Set the default {@link CacheManager} to use to lookup cache by name. Only mandatory
* if the {@linkplain CacheResolver cache resolvers} have not been set.
* Construct a new {@code DefaultJCacheOperationSource} with the default key generator.
* @see SimpleKeyGenerator
*/
public DefaultJCacheOperationSource() {
this.keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);
}
/**
* Construct a new {@code DefaultJCacheOperationSource} with the given cache manager,
* cache resolver and key generator suppliers, applying the corresponding default
* if a supplier is not resolvable.
* @since 5.1
*/
public DefaultJCacheOperationSource(
@Nullable Supplier<CacheManager> cacheManager, @Nullable Supplier<CacheResolver> cacheResolver,
@Nullable Supplier<CacheResolver> exceptionCacheResolver, @Nullable Supplier<KeyGenerator> keyGenerator) {
this.cacheManager = SingletonSupplier.ofNullable(cacheManager);
this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver);
this.exceptionCacheResolver = SingletonSupplier.ofNullable(exceptionCacheResolver);
this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new);
}
/**
* Set the default {@link CacheManager} to use to lookup cache by name.
* Only mandatory if the {@linkplain CacheResolver cache resolver} has not been set.
*/
public void setCacheManager(@Nullable CacheManager cacheManager) {
this.cacheManager = cacheManager;
this.cacheManager = SingletonSupplier.ofNullable(cacheManager);
}
/**
@@ -72,7 +105,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
*/
@Nullable
public CacheManager getCacheManager() {
return this.cacheManager;
return SupplierUtils.resolve(this.cacheManager);
}
/**
@@ -80,7 +113,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
* implementation using the specified cache manager will be used.
*/
public void setCacheResolver(@Nullable CacheResolver cacheResolver) {
this.cacheResolver = cacheResolver;
this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver);
}
/**
@@ -88,7 +121,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
*/
@Nullable
public CacheResolver getCacheResolver() {
return this.cacheResolver;
return SupplierUtils.resolve(this.cacheResolver);
}
/**
@@ -96,7 +129,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
* implementation using the specified cache manager will be used.
*/
public void setExceptionCacheResolver(@Nullable CacheResolver exceptionCacheResolver) {
this.exceptionCacheResolver = exceptionCacheResolver;
this.exceptionCacheResolver = SingletonSupplier.ofNullable(exceptionCacheResolver);
}
/**
@@ -104,7 +137,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
*/
@Nullable
public CacheResolver getExceptionCacheResolver() {
return this.exceptionCacheResolver;
return SupplierUtils.resolve(this.exceptionCacheResolver);
}
/**
@@ -112,16 +145,15 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
* honoring the JSR-107 {@link javax.cache.annotation.CacheKey} and
* {@link javax.cache.annotation.CacheValue} will be used.
*/
public void setKeyGenerator(@Nullable KeyGenerator keyGenerator) {
this.keyGenerator = keyGenerator;
public void setKeyGenerator(KeyGenerator keyGenerator) {
this.keyGenerator = SingletonSupplier.of(keyGenerator);
}
/**
* Return the specified key generator to use, if any.
* Return the specified key generator to use.
*/
@Nullable
public KeyGenerator getKeyGenerator() {
return this.keyGenerator;
return this.keyGenerator.obtain();
}
@Override
@@ -130,21 +162,17 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
}
@Override
public void afterPropertiesSet() {
this.adaptedKeyGenerator = new KeyGeneratorAdapter(this, this.keyGenerator);
}
@Override
public void afterSingletonsInstantiated() {
// Make sure that the cache resolver is initialized. An exception cache resolver is only
// required if the exceptionCacheName attribute is set on an operation
// required if the exceptionCacheName attribute is set on an operation.
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
}
@Override
protected <T> T getBean(Class<T> type) {
Assert.state(this.beanFactory != null, "BeanFactory required for resolution of [" + type + "]");
try {
return this.beanFactory.getBean(type);
}
@@ -161,9 +189,10 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
}
protected CacheManager getDefaultCacheManager() {
if (this.cacheManager == null) {
if (getCacheManager() == null) {
Assert.state(this.beanFactory != null, "BeanFactory required for default CacheManager resolution");
try {
this.cacheManager = this.beanFactory.getBean(CacheManager.class);
this.cacheManager = SingletonSupplier.of(this.beanFactory.getBean(CacheManager.class));
}
catch (NoUniqueBeanDefinitionException ex) {
throw new IllegalStateException("No unique bean of type CacheManager found. "+
@@ -174,50 +203,50 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
"bean or remove the @EnableCaching annotation from your configuration.");
}
}
return this.cacheManager;
return getCacheManager();
}
@Override
protected CacheResolver getDefaultCacheResolver() {
if (this.cacheResolver == null) {
this.cacheResolver = new SimpleCacheResolver(getDefaultCacheManager());
if (getCacheResolver() == null) {
this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(getDefaultCacheManager()));
}
return this.cacheResolver;
return getCacheResolver();
}
@Override
protected CacheResolver getDefaultExceptionCacheResolver() {
if (this.exceptionCacheResolver == null) {
this.exceptionCacheResolver = new LazyCacheResolver();
if (getExceptionCacheResolver() == null) {
this.exceptionCacheResolver = SingletonSupplier.of(new LazyCacheResolver());
}
return this.exceptionCacheResolver;
return getExceptionCacheResolver();
}
@Override
protected KeyGenerator getDefaultKeyGenerator() {
return this.adaptedKeyGenerator;
return this.adaptedKeyGenerator.obtain();
}
/**
* Only resolve the default exception cache resolver when an exception needs to be handled.
* <p>A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. If only
* the latter is specified, it is not possible to extract a default exception {@code CacheResolver}
* from a custom {@code CacheResolver} implementation so we have to fallback on the {@code CacheManager}.
* <p>This gives this weird situation of a perfectly valid configuration that breaks all the sudden
* because the JCache support is enabled. To avoid this we resolve the default exception {@code CacheResolver}
* as late as possible to avoid such hard requirement in other cases.
* <p>A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}.
* If only the latter is specified, it is not possible to extract a default exception
* {@code CacheResolver} from a custom {@code CacheResolver} implementation so we have to
* fall back on the {@code CacheManager}.
* <p>This gives this weird situation of a perfectly valid configuration that breaks all
* the sudden because the JCache support is enabled. To avoid this we resolve the default
* exception {@code CacheResolver} as late as possible to avoid such hard requirement
* in other cases.
*/
class LazyCacheResolver implements CacheResolver {
private CacheResolver cacheResolver;
private final SingletonSupplier<CacheResolver> cacheResolver =
SingletonSupplier.of(() -> new SimpleExceptionCacheResolver(getDefaultCacheManager()));
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
if (this.cacheResolver == null) {
this.cacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager());
}
return this.cacheResolver.resolveCaches(context);
return this.cacheResolver.obtain().resolveCaches(context);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -28,6 +28,7 @@ import org.springframework.cache.interceptor.AbstractCacheInvoker;
import org.springframework.cache.interceptor.BasicOperation;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheOperationInvoker;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -52,19 +53,27 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private JCacheOperationSource cacheOperationSource;
@Nullable
private CacheResultInterceptor cacheResultInterceptor;
@Nullable
private CachePutInterceptor cachePutInterceptor;
@Nullable
private CacheRemoveEntryInterceptor cacheRemoveEntryInterceptor;
@Nullable
private CacheRemoveAllInterceptor cacheRemoveAllInterceptor;
private boolean initialized = false;
private CacheResultInterceptor cacheResultInterceptor;
private CachePutInterceptor cachePutInterceptor;
private CacheRemoveEntryInterceptor cacheRemoveEntryInterceptor;
private CacheRemoveAllInterceptor cacheRemoveAllInterceptor;
/**
* Set the CacheOperationSource for this cache aspect.
*/
public void setCacheOperationSource(JCacheOperationSource cacheOperationSource) {
Assert.notNull(cacheOperationSource, "JCacheOperationSource must not be null");
this.cacheOperationSource = cacheOperationSource;
@@ -74,12 +83,13 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
* Return the CacheOperationSource for this cache aspect.
*/
public JCacheOperationSource getCacheOperationSource() {
Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSource' property is required: " +
"If there are no cacheable methods, then don't use a cache aspect.");
return this.cacheOperationSource;
}
public void afterPropertiesSet() {
Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSource' property is required: " +
"If there are no cacheable methods, then don't use a cache aspect.");
getCacheOperationSource();
this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler());
this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler());
@@ -90,6 +100,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
}
@Nullable
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
// Check whether aspect is enabled to cope with cases where the AJ is pulled in automatically
if (this.initialized) {
@@ -114,23 +125,28 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
}
@SuppressWarnings("unchecked")
@Nullable
private Object execute(CacheOperationInvocationContext<?> context, CacheOperationInvoker invoker) {
CacheOperationInvoker adapter = new CacheOperationInvokerAdapter(invoker);
BasicOperation operation = context.getOperation();
if (operation instanceof CacheResultOperation) {
Assert.state(this.cacheResultInterceptor != null, "No CacheResultInterceptor");
return this.cacheResultInterceptor.invoke(
(CacheOperationInvocationContext<CacheResultOperation>) context, adapter);
}
else if (operation instanceof CachePutOperation) {
Assert.state(this.cachePutInterceptor != null, "No CachePutInterceptor");
return this.cachePutInterceptor.invoke(
(CacheOperationInvocationContext<CachePutOperation>) context, adapter);
}
else if (operation instanceof CacheRemoveOperation) {
Assert.state(this.cacheRemoveEntryInterceptor != null, "No CacheRemoveEntryInterceptor");
return this.cacheRemoveEntryInterceptor.invoke(
(CacheOperationInvocationContext<CacheRemoveOperation>) context, adapter);
}
else if (operation instanceof CacheRemoveAllOperation) {
Assert.state(this.cacheRemoveAllInterceptor != null, "No CacheRemoveAllInterceptor");
return this.cacheRemoveAllInterceptor.invoke(
(CacheOperationInvocationContext<CacheRemoveAllOperation>) context, adapter);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -18,11 +18,16 @@ package org.springframework.cache.jcache.interceptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheOperationInvoker;
import org.springframework.cache.interceptor.SimpleCacheErrorHandler;
import org.springframework.lang.Nullable;
import org.springframework.util.function.SingletonSupplier;
/**
* AOP Alliance MethodInterceptor for declarative cache
@@ -35,13 +40,32 @@ import org.springframework.cache.interceptor.CacheOperationInvoker;
* <p>JCacheInterceptors are thread-safe.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see org.springframework.cache.interceptor.CacheInterceptor
*/
@SuppressWarnings("serial")
public class JCacheInterceptor extends JCacheAspectSupport implements MethodInterceptor, Serializable {
/**
* Construct a new {@code JCacheInterceptor} with the default error handler.
*/
public JCacheInterceptor() {
}
/**
* Construct a new {@code JCacheInterceptor} with the given error handler.
* @param errorHandler a supplier for the error handler to use,
* applying the default error handler if the supplier is not resolvable
* @since 5.1
*/
public JCacheInterceptor(@Nullable Supplier<CacheErrorHandler> errorHandler) {
this.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new);
}
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -33,7 +33,6 @@ public interface JCacheOperationSource {
/**
* Return the cache operations for this method, or {@code null}
* if the method contains no <em>JSR-107</em> related metadata.
*
* @param method the method to introspect
* @param targetClass the target class (may be {@code null}, in which case
* the declaring class of the method must be used)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
@@ -31,11 +31,10 @@ import org.springframework.util.ObjectUtils;
* @since 4.1
*/
@SuppressWarnings("serial")
public abstract class JCacheOperationSourcePointcut
extends StaticMethodMatcherPointcut implements Serializable {
public abstract class JCacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method method, Class<?> targetClass) {
public boolean matches(Method method, @Nullable Class<?> targetClass) {
JCacheOperationSource cas = getCacheOperationSource();
return (cas != null && cas.getCacheOperation(method, targetClass) != null);
}
@@ -47,6 +46,7 @@ public abstract class JCacheOperationSourcePointcut
@Nullable
protected abstract JCacheOperationSource getCacheOperationSource();
@Override
public boolean equals(Object other) {
if (this == other) {

View File

@@ -25,6 +25,7 @@ import javax.cache.annotation.CacheKeyGenerator;
import javax.cache.annotation.CacheKeyInvocationContext;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -34,14 +35,17 @@ import org.springframework.util.CollectionUtils;
* so that only relevant parameters are handled.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
*/
class KeyGeneratorAdapter implements KeyGenerator {
private final JCacheOperationSource cacheOperationSource;
@Nullable
private KeyGenerator keyGenerator;
@Nullable
private CacheKeyGenerator cacheKeyGenerator;
@@ -72,7 +76,11 @@ class KeyGeneratorAdapter implements KeyGenerator {
* or a {@link CacheKeyGenerator}.
*/
public Object getTarget() {
return (this.keyGenerator != null ? this.keyGenerator : this.cacheKeyGenerator);
if (this.cacheKeyGenerator != null) {
return this.cacheKeyGenerator;
}
Assert.state(this.keyGenerator != null, "No key generator");
return this.keyGenerator;
}
@Override
@@ -87,6 +95,7 @@ class KeyGeneratorAdapter implements KeyGenerator {
return this.cacheKeyGenerator.generateCacheKey(invocationContext);
}
else {
Assert.state(this.keyGenerator != null, "No key generator");
return doGenerate(this.keyGenerator, invocationContext);
}
}

View File

@@ -7,4 +7,9 @@
* <p>Builds on the AOP infrastructure in org.springframework.aop.framework.
* Any POJO can be cache-advised with Spring.
*/
@NonNullApi
@NonNullFields
package org.springframework.cache.jcache.interceptor;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;