前言
之前写过一篇@Async、@EnableAsync、@EnableScheduler、@Scheduled在Spring应用中的基本使用的文章。
最近在学习SpringBoot的异步任务,发现书中还提及到AsyncConfigurer
接口,之前没见过它啊-_-! 那么 这个AsyncConfigurer接口到底有什么用?我们的异步执行器配置类要不要实现它? 带着疑惑,我就去阅读了一下相关的源码,终于找到答案了。
顺便还理清楚了另一个问题:Spring到底是如何决定某个目标方法使用哪个异步执行器(线程池)的?(提前透露:用户可以指定默认的异步执行器,若没指定,Spring会进行两次兜底,第二次兜底才是使用SimpleAsyncTaskExecutor
)
注意:本文中大部分功能/源码都是Spring提供的,只有少数的是SpringBoot提供的(写有“SpringBoot”标识)。
主要流程
项目启动时
-
AsyncAnnotationBeanPostProcessor#setBeanFactory(BeanFactory beanFactory)
new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
AsyncAnnotationAdvisor#buildAdvice(executor, exceptionHandler);
-AsyncExecutionAspectSupport#configure(Supplier<Executor> defaultExecutor, Supplier<AsyncUncaughtExceptionHandler> exceptionHandler)
// 注意传入的是Supplier,下面的代码不会马上执行
-AsyncExecutionInterceptor#getDefaultExecutor(BeanFactory beanFactory)
-AsyncExecutionAspectSupport#getDefaultExecutor(BeanFactory beanFactory)
-new SimpleAsyncTaskExecutor()
-
若容器中没有
TaskExecutorBuilder
类型的bean,SpringBoot会自动注册TaskExecutorBuilder
:
TaskExecutionAutoConfiguration#taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator)
-
若容器中没有
Executor
类型的bean,SpringBoot会自动注册ThreadPoolTaskExecutor
:
TaskExecutionAutoConfiguration#applicationTaskExecutor(TaskExecutorBuilder builder)
-
若容器中没有
TaskSchedulerBuilder
类型的bean,SpringBoot会自动注册TaskSchedulerBuilder
:
TaskSchedulingAutoConfiguration#taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers)
-
若容器中没有
SchedulingConfigurer、TaskScheduler、ScheduledExecutorService
类型的bean,SpringBoot会自动注册ThreadPoolTaskScheduler
:
TaskSchedulingAutoConfiguration#taskScheduler(TaskSchedulerBuilder builder)
收到请求并执行有@Async的方法时
AsyncExecutionInterceptor#invoke(final MethodInvocation invocation)
AsyncExecutionAspectSupport#determineAsyncExecutor(Method method)
this.executors.get(method);
AnnotationAsyncExecutionInterceptor#getExecutorQualifier(Method method)
this.defaultExecutor.get();
// 若方法上没有指定异步执行器,就执行上面的那个Supplier的get()方法,获取默认异步执行器SingletonSupplier#get()
this.executors.put(method, executor);
主要流程中涉及到的类
AsyncAnnotationBeanPostProcessor
public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
private Supplier<Executor> executor;
private Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
if (this.asyncAnnotationType != null) {
advisor.setAsyncAnnotationType(this.asyncAnnotationType);
}
advisor.setBeanFactory(beanFactory);
this.advisor = advisor;
}
}
AsyncExecutionAspectSupport
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
/**
* 默认异步执行器bean的默认beanName,当找到多个或0个TaskExecutor类型的bean时会用到它
*/
public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor";
/**
* 确定目标方法的异步执行器
*/
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
// 先从缓存(Map<Method, AsyncTaskExecutor>)中找目标方法的异步执行器
AsyncTaskExecutor executor = this.executors.get(method);
// 若缓存中没有找到(第一次异步执行该方法)
if (executor == null) {
Executor targetExecutor;
// 先获取方法上指定的异步执行器
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
}
// 若方法上没有指定异步执行器,就调用项目启动时设置的那个Supplier,获取默认异步执行器(用户指定的默认异步执行器/Spring兜底的默认执行器)!!!
else {
targetExecutor = this.defaultExecutor.get();
}
if (targetExecutor == null) {
return null;
}
executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
// 将目标方法及其最终确定使用的异步执行器放入缓存中
this.executors.put(method, executor);
}
return executor;
}
public void configure(Supplier<Executor> defaultExecutor, Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
// 这里的Supplier:若用户没有指定默认执行器,就通过AsyncExecutionAspectSupport#getDefaultExecutor(this.beanFactory)获取Spring兜底的默认执行器
// 但是实际传入的是AsyncExecutionAspectSuppor的子类AsyncExecutionInterceptor,故执行的是子类的getDefaultExecutor(beanFactory)方法
this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
this.exceptionHandler = new SingletonSupplier<>(exceptionHandler, SimpleAsyncUncaughtExceptionHandler::new);
}
/**
* 用户没有指定默认异步执行器时,获取兜底的默认执行器
*/
protected Executor getDefaultExecutor(BeanFactory beanFactory) {
if (beanFactory != null) {
try {
// 从容器中找TaskExecutor类型的bean... 注意不是Executor,因为它也会与ScheduledExecutorService匹配,这对于我们的目的是不可用的。
// 注意:SpringBoot的TaskExecutionAutoConfiguration、TaskSchedulingAutoConfiguration自动注册的ThreadPoolTaskExecutor、ThreadPoolTaskScheduler都是TaskExecutor的后代类。
return beanFactory.getBean(TaskExecutor.class);
} catch (NoUniqueBeanDefinitionException ex) {
logger.debug("Could not find unique TaskExecutor bean", ex);
try {
// 如果查找到多个TaskExecutor类型的bean,就根据默认的beanName(即"taskExecutor")来筛选出一个
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
}
catch (NoSuchBeanDefinitionException ex2) {
// 如果筛选失败,则返回null(注意:子类还会再兜底)
if (logger.isInfoEnabled()) {
logger.info("More than one TaskExecutor bean found within the context, and none is named " +
"'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +
"as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());
}
}
}
catch (NoSuchBeanDefinitionException ex) {
logger.debug("Could not find default TaskExecutor bean", ex);
try {
// 如果查找到0个TaskExecutor类型的bean,就根据默认的beanName(即"taskExecutor")从容器中查找Executor类型的bean
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
}
catch (NoSuchBeanDefinitionException ex2) {
// 如果还是查找不到,就返回null(注意:子类还会再兜底)
logger.info("No task executor bean found for async processing: " +
"no bean of type TaskExecutor and no bean named 'taskExecutor' either");
}
// Giving up -> either using local default executor or none at all...
}
}
return null;
}
}
AsyncExecutionInterceptor
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 判定使用哪个异步执行器来执行目标方法
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
Callable<Object> task = () -> {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userDeclaredMethod, invocation.getArguments());
}
return null;
};
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
protected Executor getDefaultExecutor(BeanFactory beanFactory) {
// 先调用父类(AsyncExecutionAspectSupport)的方法获取默认异步执行器
Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
// 若父类方法的返回值为null,则Spring再继续兜底:创建一个SimpleAsyncTaskExecutor
// SimpleAsyncTaskExecutor:每次都会启动新的线程执行任务,并允许开发者控制并发线程的上限(concurrencyLimit),从而起到一定的资源节流作用。concurrencyLimit默认值为-1,即不启用资源节流。
return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
}
}
AnnotationAsyncExecutionInterceptor
public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionInterceptor {
protected String getExecutorQualifier(Method method) {
// Maintainer's note: changes made here should also be made in
// AnnotationAsyncExecutionAspect#getExecutorQualifier
Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
if (async == null) {
async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
}
// 返回目标方法上@Asyn注解的value属性值
return (async != null ? async.value() : null);
}
}
SingletonSupplier
public class SingletonSupplier<T> implements Supplier<T> {
// 单例对象的指定提供者
private final Supplier<? extends T> instanceSupplier;
// 单例对象的兜底提供者(当指定提供者为null时,使用它)
private final Supplier<? extends T> defaultSupplier;
// 最终的单例对象
private volatile T singletonInstance;
public SingletonSupplier(@Nullable Supplier<? extends T> instanceSupplier, Supplier<? extends T> defaultSupplier) {
this.instanceSupplier = instanceSupplier;
this.defaultSupplier = defaultSupplier;
}
/**
* 获取单例对象的优先级:singletonInstance --> instanceSupplier --> defaultSupplier
*/
public T get() {
// 先尝试直接获取singletonInstance
T instance = this.singletonInstance;
if (instance == null) {
synchronized (this) {
instance = this.singletonInstance;
// 若singletonInstance为null
if (instance == null) {
// 若instanceSupplier不为null,就使用它来生产单例对象
if (this.instanceSupplier != null) {
instance = this.instanceSupplier.get();
}
// 若单例对象还为null且defaultSupplier不为null,就使用defaultSupplier来生产单例对象
if (instance == null && this.defaultSupplier != null) {
instance = this.defaultSupplier.get();
}
// 将生产出来的单例对象赋值给singletonInstance
this.singletonInstance = instance;
}
}
}
return instance;
}
}
TaskExecutionAutoConfiguration
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
// 对应spring.task.execution
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {
/**
* Bean name of the application {@link TaskExecutor}.
*/
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
ObjectProvider<TaskDecorator> taskDecorator) {
TaskExecutionProperties.Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize(pool.getCoreSize());
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
builder = builder.taskDecorator(taskDecorator.getIfUnique());
return builder;
}
@Lazy
// 这里name属性值="applicationTaskExecutor","taskExecutor",正好AsyncExecutionAspectSupport#DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor"!!!
// 所以若用户没有手动注册过Executor类型的bean,该方法就会执行,会自动注册一个ThreadPoolTaskExecutor,name="applicationTaskExecutor",alias="taskExecutor"
// 那么AsyncExecutionAspectSupport一定能兜底成功(即默认异步执行器至少能使用到这个taskExecutor),那么它的子类AsyncExecutionInterceptor就不会后续兜底(即不会使用到SimpleAsyncTaskExecutor)!!!
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME, AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}
TaskSchedulingAutoConfiguration
@ConditionalOnClass(ThreadPoolTaskScheduler.class)
@Configuration(proxyBeanMethods = false)
// 对应spring.task.scheduling
@EnableConfigurationProperties(TaskSchedulingProperties.class)
@AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
public class TaskSchedulingAutoConfiguration {
@Bean
@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class })
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
return builder.build();
}
@Bean
@ConditionalOnMissingBean
public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties,
ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
builder = builder.poolSize(properties.getPool().getSize());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
builder = builder.customizers(taskSchedulerCustomizers);
return builder;
}
}
流程图:
AsyncExecutionAspectSupport#determineAsyncExecutor()
AsyncExecutionAspectSupport#getDefaultExecutor()
总结:
各种情况下的默认异步执行器
-
情况1.用户注册了
AsyncConfigurer
的实现类bean,并重写getAsyncExecutor()
,即指定了默认异步执行器- 在第一次执行异步任务时Spring会自动调用实现类bean的
getAsyncExecutor()
获取到它,获取到后会赋值给最终的单例对象singletonInstance
,并存入缓存Map<Method, AsyncTaskExecutor>
中。 - 注意:上面说了在第一次执行异步任务时Spring会自动调用注册的实现类bean的
getAsyncExecutor()
获取到它,所以getAsyncExecutor()
方法上不需要添加@Bean注解 - 注意:由于用户指定的默认异步执行器并不是Spring Bean,所以
getAsyncExecutor()
中必须手动执行ThreadPoolTaskExecutor#initialize()
,否则会报错:ThreadPoolTaskExecutor not initialized
- 在第一次执行异步任务时Spring会自动调用实现类bean的
-
情况2.用户没有注册过
AsyncConfigurer
的实现类,即没有指定默认异步执行器-
情况2-1.用户注册了1个
TaskExecutor
类型的bean
那么AsyncExecutionAspectSupport
兜底成功,使用该异步执行器 -
情况2-2.用户注册了多个
TaskExecutor
类型的bean- 情况2-2-1.有一个的name = “taskExecutor”
那么AsyncExecutionAspectSupport
兜底成功,使用该异步执行器 - 情况2-2-2.没有name = “taskExecutor”
那么AsyncExecutionAspectSupport
兜底失败(注意:子类AsyncExecutionInterceptor
还会再兜底,就会使用到SimpleAsyncTaskExecutor
)
- 情况2-2-1.有一个的name = “taskExecutor”
-
情况2-3.用户注册了0个
TaskExecutor
类型的bean-
情况2-3-1.用户注册过类型为
Executor
,且name = “taskExecutor” 的bean
那么AsyncExecutionAspectSupport
兜底成功,使用该异步执行器补充:这样就没必要手动注册了,直接使用情况2-3-3,在application.yml中配置即可
-
情况2-3-2.用户没有注册过类型为
Executor
,且name = “taskExecutor” 的bean
那么AsyncExecutionAspectSupport
兜底失败(注意:子类AsyncExecutionInterceptor
还会再兜底,就会使用到SimpleAsyncTaskExecutor
) -
情况2-3-3.用户没有注册过
Executor
类型的bean
那么SpringBoot会根据application.yml
的配置自动注册一个ThreadPoolTaskExecutor
,name=“applicationTaskExecutor”,alias=“taskExecutor”同理,若用户没有注册过
SchedulingConfigurer、TaskScheduler和ScheduledExecutorService
类型的bean,那么SpringBoot会根据application.yml的配置自动注册ThreadPoolTaskScheduler
那么
AsyncExecutionAspectSupport
一定能兜底成功(即默认异步执行器至少能使用到这个自动注册的taskExecutor
),那么它的子类AsyncExecutionInterceptor
就不会再兜底,就不会使用到SimpleAsyncTaskExecutor
-
-
总之分很多种情况,不同情况下兜底的默认异步执行器的结果都不一样。
-
建议:尽量不要使用到子类
AsyncExecutionInterceptor
的再兜底,也就是不要使用到SimpleAsyncTaskExecutor
,因为它不是一个好的异步执行器~
-
几种配置异步执行器的方式比较
方式 | 优点 | 缺点 |
---|---|---|
SpringBoot自动注册ThreadPoolTaskExecutor | 很简单,只需要在配置文件中配置即可 | 只支持简单配置,对于高级配置,请考虑使用TaskExecutorCustomizer |
手动注册ThreadPoolTaskExecutor | 支持复杂配置 | 无法配置UncaughtExceptionHandler (见java.lang.Thread#uncaughtExceptionHandler,java.lang.Thread#defaultUncaughtExceptionHandler,java.lang.ThreadGroup#uncaughtException ) |
手动注册AsyncConfigure-bean ,实现getExecutor() 方法 | 可以配置AsyncUncaughtExceptionHandler (见org.springframework.scheduling.annotation.AsyncConfigurer#getAsyncUncaughtExceptionHandler ),处理void返回类型的异步方法执行期间引发的异常 | 只能供@Async 使用,并没有往容器中注册ThreadPoolTaskExecutor-bean |