【Spring】Spring Async 的实现原理 2 - AsyncAnnotationAdvisor
前言
本章节主要了解 AsyncAnnotationAdvisor
,不准确的描述:Advisor
可以视为 Advice + Pointcut
,前者即执行的通知逻辑,后者即通知执行的切入点
关于 Advisor
等相关 Spring AOP API
,可以自行了解或参考链接文章
AsyncAnnotationAdvisor
public AsyncAnnotationAdvisor(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
// 指定对应的切点注解:@Async 和 javax.ejb.Asynchronous
asyncAnnotationTypes.add(Async.class);
try {
asyncAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
}
// 基于 executor 和 exceptionHandler 构建 Advice
this.advice = buildAdvice(executor, exceptionHandler);
// 基于 asyncAnnotationTypes 构建 Pointcut
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
----------------- buildAdvice
protected Advice buildAdvice(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
// 创建 AnnotationAsyncExecutionInterceptor
AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
// 基于 executor 和 exceptionHandler 配置
interceptor.configure(executor, exceptionHandler);
return interceptor;
}
------------ buildPointcut
protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
ComposablePointcut result = null;
for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
// 标记在类上
Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
// 标记在方法上
Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);
// 基于 ComposablePointcut 合并
if (result == null) {
result = new ComposablePointcut(cpc);
}
else {
result.union(cpc);
}
result = result.union(mpc);
}
return (result != null ? result : Pointcut.TRUE);
}
在构造方法中创建对应的 Advice
和 Pointcut
,分别为:
- 基于
executor
和exceptionHandler
创建配置AnnotationAsyncExecutionInterceptor
,其中:executor
即调度异步方法的Executor
执行器,exceptionHandler
负责处理调度异常 Pointcut
根据注解@Async
和javax.ejb.Asynchronous
构造,可以标注在类和方法上,最终构造的是以上的并集ComposablePointcut
接下来是对 AnnotationAsyncExecutionInterceptor
的具体了解
AnnotationAsyncExecutionInterceptor
AsyncExecutionAspectSupport
public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {
this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
this.exceptionHandler = SingletonSupplier.of(exceptionHandler);
}
AsyncExecutionAspectSupport
是异步执行切面的基类,构造时允许指定默认的执行器- 其中
getDefaultExecutor
方法代码略,逻辑为:从容器中获取唯一的type = TaskExecutor
或name = taskExecutor
的bean
实例,否则返回null
,因此我们在 部分场景 使用Spring Async
可以直接注册TaskExecutor
实例来充当异步方法的执行器
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
// 缓存中获取
AsyncTaskExecutor executor = this.executors.get(method);
if (executor == null) {
Executor targetExecutor;
// 获取对应方法的执行器限定符
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
// 限定符不为空,则获取对应的执行器
targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
}
else {
// 否则获取默认的执行器
targetExecutor = this.defaultExecutor.get();
}
if (targetExecutor == null) {
return null;
}
// 适配执行器为 AsyncListenableTaskExecutor
executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
this.executors.put(method, executor);
}
return executor;
}
determineAsyncExecutor
方法主要是为指定方法推断对应的 执行器
来执行,大体逻辑概括:
- 先从缓存获取,第一次肯定为空
- 基于
getExecutorQualifier
来获取目标方法的执行器限定符
,该方法主要由子类实现,比如取自@Async
注解的属性 - 上述步骤获取的限定符不为空,则由方法
findQualifiedExecutor
获取对应的执行器
,通常可以理解为基于beanName
从容器中获取 - 否则使用默认的执行器
- 执行器被适配成
AsyncListenableTaskExecutor
并缓存
AsyncExecutionInterceptor
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {
// ...
}
AsyncExecutionInterceptor
同时也是一个 MethodInterceptor
,因此通知逻辑聚焦于 invoke
方法
public Object invoke(final MethodInvocation invocation) throws Throwable {
// ...
// 获取对应方法的执行器
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
// ...
}
// 用 Callable 包装目标方法
Callable<Object> task = () -> {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (ExecutionException ex) {
// ...
}
return null;
};
// 最终交给执行器调度
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
- 基于方法获取对应的执行器,
determineAsyncExecutor
即上文其父类定义的模板方法
- 将目标方法包装成
Callable
后由该执行器调度
// 获取方法的执行器限定符,未实现
protected String getExecutorQualifier(Method method) {
return null;
}
@Nullable
// 提供默认执行器 SimpleAsyncTaskExecutor
protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {
Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
}
- 该类未实现
getExecutorQualifier
方法 - 该类提供默认执行器为
SimpleAsyncTaskExecutor
而非父类的null
AnnotationAsyncExecutionInterceptor
@Override
@Nullable
protected String getExecutorQualifier(Method method) {
// 从 @Async 注解上解析执行器限定符,即 value 属性
Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
if (async == null) {
async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
}
return (async != null ? async.value() : null);
}
- 留给子类
AnnotationAsyncExecutionInterceptor
的任务就只有实现getExecutorQualifier
方法了,用以获取指定方法的执行器限定符 - 此处的实现就是获取注解
@Async
的value
属性
总结
本文主要是了解 AsyncAnnotationAdvisor
的细节,若视为 Advisor = Advice + Pointcut
,则:
- 对应的
Advice
为AnnotationAsyncExecutionInterceptor
- 对应的
Pointcut
即基于类和方法的注解(@Async
javax.ejb.Asynchronous
)匹配
其中,AnnotationAsyncExecutionInterceptor
主要有两个方面:
- 作为一个
AsyncExecutionAspectSupport
,它实现了getExecutorQualifier
,可以从注解(@Async
javax.ejb.Asynchronous
)上解析执行器限定符来指定具体的执行器,否则使用默认(全局)执行器 - 作为一个
MethodInterceptor
,也是通知逻辑的实现,它将目标方法包装成Callable
交给对应的执行器调度
至此,Spring Async
实现的核心逻辑类已了解的差不多了,下一章节会梳理基于 @EnabledAsync
引入 Spring Async
框架的整体流程