【Spring】Spring Async 的实现原理 2 - AsyncAnnotationAdvisor

前言

本章节主要了解 AsyncAnnotationAdvisor,不准确的描述:Advisor 可以视为 Advice + Pointcut,前者即执行的通知逻辑,后者即通知执行的切入点

关于 Advisor 等相关 Spring AOP API,可以自行了解或参考链接文章

【源码】Spring AOP 5 Advisor

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);
	}

在构造方法中创建对应的 AdvicePointcut,分别为:

  • 基于 executorexceptionHandler 创建配置 AnnotationAsyncExecutionInterceptor,其中:executor 即调度异步方法的 Executor 执行器,exceptionHandler 负责处理调度异常
  • Pointcut 根据注解 @Asyncjavax.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 = TaskExecutorname = taskExecutorbean 实例,否则返回 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 方法主要是为指定方法推断对应的 执行器 来执行,大体逻辑概括:

  1. 先从缓存获取,第一次肯定为空
  2. 基于 getExecutorQualifier 来获取目标方法的 执行器限定符,该方法主要由子类实现,比如取自 @Async 注解的属性
  3. 上述步骤获取的限定符不为空,则由方法 findQualifiedExecutor 获取对应的 执行器,通常可以理解为基于 beanName 从容器中获取
  4. 否则使用默认的执行器
  5. 执行器被适配成 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());
	}
  1. 基于方法获取对应的执行器,determineAsyncExecutor 即上文其父类定义的 模板方法
  2. 将目标方法包装成 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 方法了,用以获取指定方法的执行器限定符
  • 此处的实现就是获取注解 @Asyncvalue 属性

总结

本文主要是了解 AsyncAnnotationAdvisor 的细节,若视为 Advisor = Advice + Pointcut,则:

  • 对应的 AdviceAnnotationAsyncExecutionInterceptor
  • 对应的 Pointcut 即基于类和方法的注解(@Async javax.ejb.Asynchronous)匹配

其中,AnnotationAsyncExecutionInterceptor 主要有两个方面:

  1. 作为一个 AsyncExecutionAspectSupport,它实现了 getExecutorQualifier,可以从注解(@Async javax.ejb.Asynchronous)上解析执行器限定符来指定具体的执行器,否则使用默认(全局)执行器
  2. 作为一个 MethodInterceptor,也是通知逻辑的实现,它将目标方法包装成 Callable 交给对应的执行器调度

至此,Spring Async 实现的核心逻辑类已了解的差不多了,下一章节会梳理基于 @EnabledAsync 引入 Spring Async 框架的整体流程

上一篇:【Spring】Spring Async 的实现原理 1 - ProxyProcessorSupport

下一篇:【Spring】Spring Async 的实现原理 3 - 整体实现流程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值