栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

前言AsyncAnnotationAdvisor

AnnotationAsyncExecutionInterceptor

AsyncExecutionAspectSupportAsyncExecutionInterceptorAnnotationAsyncExecutionInterceptor 总结

前言

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

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

【源码】Spring AOP 5 Advisor

AsyncAnnotationAdvisor
	public AsyncAnnotationAdvisor(
			@Nullable Supplier executor, @Nullable Supplier exceptionHandler) {

		Set> asyncAnnotationTypes = new linkedHashSet<>(2);

		// 指定对应的切点注解:@Async 和 javax.ejb.Asynchronous
		asyncAnnotationTypes.add(Async.class);
		try {
			asyncAnnotationTypes.add((Class)
					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, @Nullable Supplier exceptionHandler) {

		// 创建 AnnotationAsyncExecutionInterceptor
		AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);

		//  基于 executor 和 exceptionHandler 配置
		interceptor.configure(executor, exceptionHandler);
		return interceptor;
	}

	------------ buildPointcut

	protected Pointcut buildPointcut(Set> asyncAnnotationTypes) {
		ComposablePointcut result = null;
		for (Class 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 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 框架的整体流程

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

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

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号