【Spring】Spring Async 的实现原理 3 - 整体实现流程

  • 前言
  • @EnableAsync
  • AsyncConfigurationSelector
  • AdviceModeImportSelector
  • AsyncConfigurationSelector
  • ProxyAsyncConfiguration
  • AbstractAsyncConfiguration
  • ProxyAsyncConfiguration
  • 总结


前言

本章节从引入 Spring Async@EnableAsync 注解入手,了解下整个引入流程

@EnableAsync

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

	// spring async 的注解类型
	Class<? extends Annotation> annotation() default Annotation.class;

	// 影响代理方式(JDK or CGLIB)
	boolean proxyTargetClass() default false;

	// 基于 代理 或 AspectJ 的通知模式,默认就是前者
	AdviceMode mode() default AdviceMode.PROXY;

	// 排序值
	int order() default Ordered.LOWEST_PRECEDENCE;

}
  • 一些通知相关的核心属性
  • 重点是 import 了配置类 AsyncConfigurationSelector,会引入一些必要 配置类

AsyncConfigurationSelector

AdviceModeImportSelector

public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {

	// ...
	
	@Override
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {

		// 获取泛型注解类
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);

		// 获取该注解的属性
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);

		// 获取 mode 属性
		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());

		// 子类基于 mode 引入对于的配置类
		String[] imports = selectImports(adviceMode);
		return imports;
	}

	/**
	 * 有子类实现基于 mode 属性引入对应 配置类
	 */
	@Nullable
	protected abstract String[] selectImports(AdviceMode adviceMode);

}

AdviceModeImportSelector,基于注解 AdviceMode mode 属性引入对应配置类的基类 :

  • 它是一个 ImportSelector,因此支持配置类的引入,此处会基于注解的属性解析 AdviceMode mode 属性
  • selectImports 方法交给子类,基于 mode 属性引入对应的配置类,Spring Async Spring Cache 等都有对应的实现
  • 比如此处 @EnableAsync 引入的 AsyncConfigurationSelector 就是它对 Spring Async 相关配置类的引入

AsyncConfigurationSelector

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	// ...
	
	@Override
	@Nullable
	public String[] selectImports(AdviceMode adviceMode) {
		
		// 该属性从注解元数据获取
		switch (adviceMode) {
			case PROXY:
				return new String[] {ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}

}
  • 通常情况下,注册的配置类为 ProxyAsyncConfiguration

ProxyAsyncConfiguration

AbstractAsyncConfiguration

@Configuration(proxyBeanMethods = false)
public abstract class AbstractAsyncConfiguration implements ImportAware {

	// ...
	
	// 获取容器中的 AsyncConfigurer
	@Autowired
	void setConfigurers(ObjectProvider<AsyncConfigurer> configurers) {
		Supplier<AsyncConfigurer> configurer = SingletonSupplier.of(() -> {
			List<AsyncConfigurer> candidates = configurers.stream().collect(Collectors.toList());
			if (CollectionUtils.isEmpty(candidates)) {
				return null;
			}
			if (candidates.size() > 1) {
				throw new IllegalStateException("Only one AsyncConfigurer may exist");
			}
			return candidates.get(0);
		});

		// 如果有且仅有一个 AsyncConfigurer 实例,则从中解析 executor 和 exceptionHandler
		this.executor = adapt(configurer, AsyncConfigurer::getAsyncExecutor);
		this.exceptionHandler = adapt(configurer, AsyncConfigurer::getAsyncUncaughtExceptionHandler);
	}

 	// ...

}
  • 父类 AbstractAsyncConfigurationSpring Async 配置基类,此处允许用户提供一个唯一的 AsyncConfigurer 配置类,从中获取对应的 executorexceptionHandler
  • 如果不提供,则最终执行器的解析如之前所述会默认从容器中获取容器中唯一 type = TaskExecutorname = taskExecutorbean 实例,否则默认 SimpleAsyncTaskExecutor
  • 不能提供多个 AsyncConfigurer,否则报错
  • 这种管理配置类的模式在 Spring 中很常见,比如 Spring Cache 也是由配置基类 AbstractCachingConfiguration 收集容器中唯一的 CacheConfigurer 配置对应属性
  • 因此,我们自定义的配置类可以实现 AsyncConfigurer 接口或继承 AsyncConfigurerSupport 类提供对属性的配置

ProxyAsyncConfiguration

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
		
		// 注册一个 AsyncAnnotationBeanPostProcessor
		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);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}

}
  • 子类 ProxyAsyncConfiguration 中默认注册一个 AsyncAnnotationBeanPostProcessor
  • 关于 AsyncAnnotationBeanPostProcessor 前文已经了解,是 ProxyProcessorSupport 的一个核心分支,其下会指定一个 AsyncAnnotationAdvisor 来完成代理通知逻辑实现最终的 Spring Async

总结

至此,对 Spring Async 的使用及其实现原理总结如下:

  1. 引入 @EnableAsync 注解,最佳实践下应该提供自定义配置类 AsyncConfigurer 来完成 执行器 的配置
  2. 引入的 @EnableAsync 注解最终会基于 AsyncConfigurer 来配置默认(全局)执行器和 AsyncUncaughtExceptionHandler
  3. 同时,会注册一个 AsyncAnnotationBeanPostProcessor 到容器中
  4. AsyncAnnotationBeanPostProcessorProxyProcessorSupport 的一个核心分支,其下会指定一个 AsyncAnnotationAdvisor
  5. AsyncAnnotationAdvisorAnnotationAsyncExecutionInterceptor 和基于注解匹配的 Pointcut 组成
  6. AnnotationAsyncExecutionInterceptor 实现将对应的异步方法交给对应的执行器调度,同时还支持 @Asyncvalue 属性指定具体执行器

上一篇:【Spring】Spring Async 的实现原理 2 - AsyncAnnotationAdvisor