在Springboot 项目中,使用 @EnableAsync 可以开启异步请求 ,使用 @Async 可以标注需要异步执行的方法,那到底是如何实现的的呢?
首先:从入口 @EnableAsync 源码查看
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Class extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
代码中声明了:
AdviceMode mode() default AdviceMode.PROXY;
并且导入了:AsyncConfigurationSelector.class
查看 AsyncConfigurationSelector 继承 AdviceModeImportSelector , AdviceModeImportSelector 实现了 ImportSelector ,
ImportSelector 接口只有一个方法:作用是根据参数AnnotationMetadata ,确定应该使用哪个配置类。
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
继续回来查看 AsyncConfigurationSelector 重写了 selectImports 方法,根据参数AdviceMode的值选择:ProxyAsyncConfiguration 还是 AspectJAsyncConfiguration,参数AdiviceMode 是根据 EnableAsync#mode的值确定,前面看到 EnableAsync 定义的mode 为 AdviceMode.PROXY 。
进入到 ProxyAsyncConfiguration , 继承了 AbstractAsyncConfiguration , 声明了一个Bean。
AbstractAsyncConfiguration 实现了 ImportAware 接口,
有两个方法 setImportMetadata ,setConfigurers
setImportMetadata 是实现接口ImportAware的方法,在方法中获取可以获取 EnableAsync 的注解属性,并赋值到 AbstractAsyncConfiguration 的属性 enableAsync 上 。
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
if (this.enableAsync == null) {
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
方法 setConfigurers 代码如下:
/**
* Collect any {@link AsyncConfigurer} beans through autowiring.
*/
@Autowired(required = false)
void setConfigurers(Collection configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException("Only one AsyncConfigurer may exist");
}
AsyncConfigurer configurer = configurers.iterator().next();
this.executor = configurer::getAsyncExecutor;
this.exceptionHandler = configurer::getAsyncUncaughtExceptionHandler;
}
从spring 容器中获取configurers ,并赋值给 executor,exceptionHandler ,跟进AsyncConfigurer 实现类,发现其返回的都是null,所以暂时不管。此时 AbstractAsyncConfiguration 里面只包含 EnableAsync 注解属性的值,其他什么都没干,继续返回 ProxyAsyncConfiguration ,跟进 AsyncAnnotationBeanPostProcesson 。
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
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.getNumber("order"));
return bpp;
}
从源码中看出看到实例化的 AsyncAnnotationBeanPostProcessor 主要是根据 EnableAsync 配置信息 , EnableAsync 默认配置信息如下:
annotation:Annotation.class
proxyTargetClass:false
order:Ordered.LOWEST_PRECEDENCE
至此,好像没有了头绪,实例化AsyncAnnotationBeanPostProcessor 就没了,只能继续看看AsyncAnnotationBeanPostProcessor 干了什么操作了,查看该类的类图和方法列表如下:
该类的父类实现了BeanFactoryAware接口,该接口声明的方法 setBeanFactory 会在初始化Bean的时候执行,去查看该类的 setBeanFactory 方法如下:
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
if (this.asyncAnnotationType != null) {
advisor.setAsyncAnnotationType(this.asyncAnnotationType);
}
advisor.setBeanFactory(beanFactory);
this.advisor = advisor;
}
未完,待续