【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);
}
// ...
}
- 父类
AbstractAsyncConfiguration
是Spring Async
配置基类,此处允许用户提供一个唯一的AsyncConfigurer
配置类,从中获取对应的executor
和exceptionHandler
- 如果不提供,则最终执行器的解析如之前所述会默认从容器中获取容器中唯一
type = TaskExecutor
或name = taskExecutor
的bean
实例,否则默认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
的使用及其实现原理总结如下:
- 引入
@EnableAsync
注解,最佳实践下应该提供自定义配置类AsyncConfigurer
来完成执行器
的配置 - 引入的
@EnableAsync
注解最终会基于AsyncConfigurer
来配置默认(全局)执行器和AsyncUncaughtExceptionHandler
- 同时,会注册一个
AsyncAnnotationBeanPostProcessor
到容器中 -
AsyncAnnotationBeanPostProcessor
是ProxyProcessorSupport
的一个核心分支,其下会指定一个AsyncAnnotationAdvisor
-
AsyncAnnotationAdvisor
由AnnotationAsyncExecutionInterceptor
和基于注解匹配的Pointcut
组成 -
AnnotationAsyncExecutionInterceptor
实现将对应的异步方法交给对应的执行器调度,同时还支持@Async
的value
属性指定具体执行器
上一篇:【Spring】Spring Async 的实现原理 2 - AsyncAnnotationAdvisor