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:
@@ -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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cache.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see EnableCaching
|
||||
*/
|
||||
@@ -46,16 +48,16 @@ public abstract class AbstractCachingConfiguration implements ImportAware {
|
||||
protected AnnotationAttributes enableCaching;
|
||||
|
||||
@Nullable
|
||||
protected CacheManager cacheManager;
|
||||
protected Supplier<CacheManager> cacheManager;
|
||||
|
||||
@Nullable
|
||||
protected CacheResolver cacheResolver;
|
||||
protected Supplier<CacheResolver> cacheResolver;
|
||||
|
||||
@Nullable
|
||||
protected KeyGenerator keyGenerator;
|
||||
protected Supplier<KeyGenerator> keyGenerator;
|
||||
|
||||
@Nullable
|
||||
protected CacheErrorHandler errorHandler;
|
||||
protected Supplier<CacheErrorHandler> errorHandler;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -87,10 +89,10 @@ public abstract class AbstractCachingConfiguration implements ImportAware {
|
||||
* Extract the configuration from the nominated {@link CachingConfigurer}.
|
||||
*/
|
||||
protected void useCachingConfigurer(CachingConfigurer config) {
|
||||
this.cacheManager = config.cacheManager();
|
||||
this.cacheResolver = config.cacheResolver();
|
||||
this.keyGenerator = config.keyGenerator();
|
||||
this.errorHandler = config.errorHandler();
|
||||
this.cacheManager = config::cacheManager;
|
||||
this.cacheResolver = config::cacheResolver;
|
||||
this.keyGenerator = config::keyGenerator;
|
||||
this.errorHandler = config::errorHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -40,13 +40,13 @@ public class CachingConfigurerSupport implements CachingConfigurer {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public KeyGenerator keyGenerator() {
|
||||
public CacheResolver cacheResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CacheResolver cacheResolver() {
|
||||
public KeyGenerator keyGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.context.annotation.Role;
|
||||
* to enable proxy-based annotation-driven cache management.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see EnableCaching
|
||||
* @see CachingConfigurationSelector
|
||||
@@ -61,19 +62,8 @@ public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public CacheInterceptor cacheInterceptor() {
|
||||
CacheInterceptor interceptor = new CacheInterceptor();
|
||||
interceptor.setCacheOperationSources(cacheOperationSource());
|
||||
if (this.cacheResolver != null) {
|
||||
interceptor.setCacheResolver(this.cacheResolver);
|
||||
}
|
||||
else if (this.cacheManager != null) {
|
||||
interceptor.setCacheManager(this.cacheManager);
|
||||
}
|
||||
if (this.keyGenerator != null) {
|
||||
interceptor.setKeyGenerator(this.keyGenerator);
|
||||
}
|
||||
if (this.errorHandler != null) {
|
||||
interceptor.setErrorHandler(this.errorHandler);
|
||||
}
|
||||
interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
|
||||
interceptor.setCacheOperationSource(cacheOperationSource());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,21 +112,21 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
*/
|
||||
private static void parseCacheResolution(Element element, BeanDefinition def, boolean setBoth) {
|
||||
String name = element.getAttribute("cache-resolver");
|
||||
if (StringUtils.hasText(name)) {
|
||||
boolean hasText = StringUtils.hasText(name);
|
||||
if (hasText) {
|
||||
def.getPropertyValues().add("cacheResolver", new RuntimeBeanReference(name.trim()));
|
||||
}
|
||||
if (!StringUtils.hasText(name) || setBoth) {
|
||||
if (!hasText || setBoth) {
|
||||
def.getPropertyValues().add("cacheManager",
|
||||
new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
|
||||
}
|
||||
}
|
||||
|
||||
private static BeanDefinition parseErrorHandler(Element element, BeanDefinition def) {
|
||||
private static void parseErrorHandler(Element element, BeanDefinition def) {
|
||||
String name = element.getAttribute("error-handler");
|
||||
if (StringUtils.hasText(name)) {
|
||||
def.getPropertyValues().add("errorHandler", new RuntimeBeanReference(name.trim()));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,27 +18,28 @@ package org.springframework.cache.interceptor;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* A base component for invoking {@link Cache} operations and using a
|
||||
* configurable {@link CacheErrorHandler} when an exception occurs.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see org.springframework.cache.interceptor.CacheErrorHandler
|
||||
*/
|
||||
public abstract class AbstractCacheInvoker {
|
||||
|
||||
private CacheErrorHandler errorHandler;
|
||||
protected SingletonSupplier<CacheErrorHandler> errorHandler;
|
||||
|
||||
|
||||
protected AbstractCacheInvoker() {
|
||||
this.errorHandler = new SimpleCacheErrorHandler();
|
||||
this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new);
|
||||
}
|
||||
|
||||
protected AbstractCacheInvoker(CacheErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
this.errorHandler = SingletonSupplier.of(errorHandler);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,15 +49,14 @@ public abstract class AbstractCacheInvoker {
|
||||
* is used who throws any exception as is.
|
||||
*/
|
||||
public void setErrorHandler(CacheErrorHandler errorHandler) {
|
||||
Assert.notNull(errorHandler, "CacheErrorHandler must not be null");
|
||||
this.errorHandler = errorHandler;
|
||||
this.errorHandler = SingletonSupplier.of(errorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CacheErrorHandler} to use.
|
||||
*/
|
||||
public CacheErrorHandler getErrorHandler() {
|
||||
return this.errorHandler;
|
||||
return this.errorHandler.obtain();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -40,9 +40,17 @@ public abstract class AbstractCacheResolver implements CacheResolver, Initializi
|
||||
private CacheManager cacheManager;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new {@code AbstractCacheResolver}.
|
||||
* @see #setCacheManager
|
||||
*/
|
||||
protected AbstractCacheResolver() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@code AbstractCacheResolver} for the given {@link CacheManager}.
|
||||
* @param cacheManager the CacheManager to use
|
||||
*/
|
||||
protected AbstractCacheResolver(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -52,6 +53,8 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.util.function.SupplierUtils;
|
||||
|
||||
/**
|
||||
* Base class for caching aspects, such as the {@link CacheInterceptor} or an
|
||||
@@ -89,10 +92,10 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
@Nullable
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private KeyGenerator keyGenerator = new SimpleKeyGenerator();
|
||||
private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);
|
||||
|
||||
@Nullable
|
||||
private CacheResolver cacheResolver;
|
||||
private SingletonSupplier<CacheResolver> cacheResolver;
|
||||
|
||||
@Nullable
|
||||
private BeanFactory beanFactory;
|
||||
@@ -100,10 +103,27 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
private boolean initialized = false;
|
||||
|
||||
|
||||
/**
|
||||
* Configure this aspect with the given error handler, key generator and cache resolver/manager
|
||||
* suppliers, applying the corresponding default if a supplier is not resolvable.
|
||||
* @since 5.1
|
||||
*/
|
||||
public void configure(
|
||||
@Nullable Supplier<CacheErrorHandler> errorHandler, @Nullable Supplier<KeyGenerator> keyGenerator,
|
||||
@Nullable Supplier<CacheResolver> cacheResolver, @Nullable Supplier<CacheManager> cacheManager) {
|
||||
|
||||
this.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new);
|
||||
this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new);
|
||||
this.cacheResolver = new SingletonSupplier<>(cacheResolver,
|
||||
() -> SimpleCacheResolver.of(SupplierUtils.resolve(cacheManager)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set one or more cache operation sources which are used to find the cache
|
||||
* attributes. If more than one source is provided, they will be aggregated
|
||||
* using a {@link CompositeCacheOperationSource}.
|
||||
* @see #setCacheOperationSource
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
|
||||
@@ -111,6 +131,15 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CacheOperationSource for this cache aspect.
|
||||
* @since 5.1
|
||||
* @see #setCacheOperationSources
|
||||
*/
|
||||
public void setCacheOperationSource(@Nullable CacheOperationSource cacheOperationSource) {
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CacheOperationSource for this cache aspect.
|
||||
*/
|
||||
@@ -125,14 +154,14 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
* <p>The default is a {@link SimpleKeyGenerator}.
|
||||
*/
|
||||
public void setKeyGenerator(KeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.keyGenerator = SingletonSupplier.of(keyGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default {@link KeyGenerator} that this cache aspect delegates to.
|
||||
*/
|
||||
public KeyGenerator getKeyGenerator() {
|
||||
return this.keyGenerator;
|
||||
return this.keyGenerator.obtain();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +173,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
* @see SimpleCacheResolver
|
||||
*/
|
||||
public void setCacheResolver(@Nullable CacheResolver cacheResolver) {
|
||||
this.cacheResolver = cacheResolver;
|
||||
this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +181,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
*/
|
||||
@Nullable
|
||||
public CacheResolver getCacheResolver() {
|
||||
return this.cacheResolver;
|
||||
return SupplierUtils.resolve(this.cacheResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +191,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
* @see SimpleCacheResolver
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheResolver = new SimpleCacheResolver(cacheManager);
|
||||
this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(cacheManager));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,8 +221,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
|
||||
"CacheManager found. Mark one as primary (or give it the name 'cacheManager') or " +
|
||||
"declare a specific CacheManager to use, that serves as the default one.");
|
||||
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A simple {@link CacheResolver} that resolves the {@link Cache} instance(s)
|
||||
@@ -27,14 +28,23 @@ import org.springframework.cache.CacheManager;
|
||||
* cache(s) as provided by {@link BasicOperation#getCacheNames() getCacheNames()}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see BasicOperation#getCacheNames()
|
||||
*/
|
||||
public class SimpleCacheResolver extends AbstractCacheResolver {
|
||||
|
||||
/**
|
||||
* Construct a new {@code SimpleCacheResolver}.
|
||||
* @see #setCacheManager
|
||||
*/
|
||||
public SimpleCacheResolver() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@code SimpleCacheResolver} for the given {@link CacheManager}.
|
||||
* @param cacheManager the CacheManager to use
|
||||
*/
|
||||
public SimpleCacheResolver(CacheManager cacheManager) {
|
||||
super(cacheManager);
|
||||
}
|
||||
@@ -45,4 +55,16 @@ public class SimpleCacheResolver extends AbstractCacheResolver {
|
||||
return context.getOperation().getCacheNames();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code SimpleCacheResolver} for the given {@link CacheManager}.
|
||||
* @param cacheManager the CacheManager (potentially {@code null})
|
||||
* @return the SimpleCacheResolver ({@code null} if the CacheManager was {@code null})
|
||||
* @since 5.1
|
||||
*/
|
||||
@Nullable
|
||||
static SimpleCacheResolver of(@Nullable CacheManager cacheManager) {
|
||||
return (cacheManager != null ? new SimpleCacheResolver(cacheManager) : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,6 +18,7 @@ package org.springframework.scheduling.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* Spring's asynchronous method execution capability.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
* @see EnableAsync
|
||||
@@ -44,10 +46,10 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
|
||||
protected AnnotationAttributes enableAsync;
|
||||
|
||||
@Nullable
|
||||
protected Executor executor;
|
||||
protected Supplier<Executor> executor;
|
||||
|
||||
@Nullable
|
||||
protected AsyncUncaughtExceptionHandler exceptionHandler;
|
||||
protected Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -72,8 +74,8 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
|
||||
throw new IllegalStateException("Only one AsyncConfigurer may exist");
|
||||
}
|
||||
AsyncConfigurer configurer = configurers.iterator().next();
|
||||
this.executor = configurer.getAsyncExecutor();
|
||||
this.exceptionHandler = configurer.getAsyncUncaughtExceptionHandler();
|
||||
this.executor = configurer::getAsyncExecutor;
|
||||
this.exceptionHandler = configurer::getAsyncUncaughtExceptionHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -21,12 +21,12 @@ import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
|
||||
@@ -35,6 +35,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Advisor that activates asynchronous method execution through the {@link Async}
|
||||
@@ -54,8 +55,6 @@ import org.springframework.util.ClassUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
private AsyncUncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
private Advice advice;
|
||||
|
||||
private Pointcut pointcut;
|
||||
@@ -65,7 +64,7 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
* Create a new {@code AsyncAnnotationAdvisor} for bean-style configuration.
|
||||
*/
|
||||
public AsyncAnnotationAdvisor() {
|
||||
this(null, null);
|
||||
this((Supplier<Executor>) null, (Supplier<AsyncUncaughtExceptionHandler>) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +76,25 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
public AsyncAnnotationAdvisor(
|
||||
@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
|
||||
this(SingletonSupplier.ofNullable(executor), SingletonSupplier.ofNullable(exceptionHandler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncAnnotationAdvisor} for the given task executor.
|
||||
* @param executor the task executor to use for asynchronous methods
|
||||
* (can be {@code null} to trigger default executor resolution)
|
||||
* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use to
|
||||
* handle unexpected exception thrown by asynchronous method executions
|
||||
* @since 5.1
|
||||
* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public AsyncAnnotationAdvisor(
|
||||
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
|
||||
|
||||
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
|
||||
asyncAnnotationTypes.add(Async.class);
|
||||
try {
|
||||
@@ -87,24 +104,11 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
catch (ClassNotFoundException ex) {
|
||||
// If EJB 3.1 API not present, simply ignore.
|
||||
}
|
||||
if (exceptionHandler != null) {
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
else {
|
||||
this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
|
||||
}
|
||||
this.advice = buildAdvice(executor, this.exceptionHandler);
|
||||
this.advice = buildAdvice(executor, exceptionHandler);
|
||||
this.pointcut = buildPointcut(asyncAnnotationTypes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the default task executor to use for asynchronous methods.
|
||||
*/
|
||||
public void setTaskExecutor(Executor executor) {
|
||||
this.advice = buildAdvice(executor, this.exceptionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'async' annotation type.
|
||||
* <p>The default async annotation type is the {@link Async} annotation, as well
|
||||
@@ -143,8 +147,12 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
}
|
||||
|
||||
|
||||
protected Advice buildAdvice(@Nullable Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
|
||||
protected Advice buildAdvice(
|
||||
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
|
||||
|
||||
AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
|
||||
interceptor.configure(executor, exceptionHandler);
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,6 +18,7 @@ package org.springframework.scheduling.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Bean post-processor that automatically applies asynchronous invocation
|
||||
@@ -75,14 +77,15 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAd
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Nullable
|
||||
private Supplier<Executor> executor;
|
||||
|
||||
@Nullable
|
||||
private Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;
|
||||
|
||||
@Nullable
|
||||
private Class<? extends Annotation> asyncAnnotationType;
|
||||
|
||||
@Nullable
|
||||
private Executor executor;
|
||||
|
||||
@Nullable
|
||||
private AsyncUncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
|
||||
public AsyncAnnotationBeanPostProcessor() {
|
||||
@@ -90,6 +93,40 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAd
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure this post-processor with the given executor and exception handler suppliers,
|
||||
* applying the corresponding default if a supplier is not resolvable.
|
||||
* @since 5.1
|
||||
*/
|
||||
public void configure(
|
||||
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
|
||||
|
||||
this.executor = executor;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link Executor} to use when invoking methods asynchronously.
|
||||
* <p>If not specified, default executor resolution will apply: searching for a
|
||||
* unique {@link TaskExecutor} bean in the context, or for an {@link Executor}
|
||||
* bean named "taskExecutor" otherwise. If neither of the two is resolvable,
|
||||
* a local default executor will be created within the interceptor.
|
||||
* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
|
||||
* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
|
||||
*/
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = SingletonSupplier.of(executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AsyncUncaughtExceptionHandler} to use to handle uncaught
|
||||
* exceptions thrown by asynchronous method executions.
|
||||
* @since 4.1
|
||||
*/
|
||||
public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
this.exceptionHandler = SingletonSupplier.of(exceptionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'async' annotation type to be detected at either class or method
|
||||
* level. By default, both the {@link Async} annotation and the EJB 3.1
|
||||
@@ -104,29 +141,6 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAd
|
||||
this.asyncAnnotationType = asyncAnnotationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link Executor} to use when invoking methods asynchronously.
|
||||
* <p>If not specified, default executor resolution will apply: searching for a
|
||||
* unique {@link TaskExecutor} bean in the context, or for an {@link Executor}
|
||||
* bean named "taskExecutor" otherwise. If neither of the two is resolvable,
|
||||
* a local default executor will be created within the interceptor.
|
||||
* @see AsyncAnnotationAdvisor#AsyncAnnotationAdvisor(Executor, AsyncUncaughtExceptionHandler)
|
||||
* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
|
||||
* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
|
||||
*/
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AsyncUncaughtExceptionHandler} to use to handle uncaught
|
||||
* exceptions thrown by asynchronous method executions.
|
||||
* @since 4.1
|
||||
*/
|
||||
public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
|
||||
@@ -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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see EnableAsync
|
||||
* @see AsyncConfigurationSelector
|
||||
@@ -45,16 +46,11 @@ public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
|
||||
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
|
||||
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
|
||||
bpp.configure(this.executor, this.exceptionHandler);
|
||||
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
|
||||
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
|
||||
bpp.setAsyncAnnotationType(customAsyncAnnotation);
|
||||
}
|
||||
if (this.executor != null) {
|
||||
bpp.setExecutor(this.executor);
|
||||
}
|
||||
if (this.exceptionHandler != null) {
|
||||
bpp.setExceptionHandler(this.exceptionHandler);
|
||||
}
|
||||
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
|
||||
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
|
||||
return bpp;
|
||||
|
||||
Reference in New Issue
Block a user