从本文开始,就正式进入源码追踪阶段了,上一篇的最后我们提到了 @EnableAsync
注解上的 @Import(AsyncConfigurationSelector.class)
了,本文就来看下它,源码如下:
package org.springframework.scheduling.annotation;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AdviceModeImportSelector;
import org.springframework.lang.Nullable;
/**
* Selects which implementation of {@link AbstractAsyncConfiguration} should be used based
* on the value of {@link EnableAsync#mode} on the importing {@code @Configuration} class.
*
* @author Chris Beams
* @since 3.1
* @see EnableAsync
* @see ProxyAsyncConfiguration
*/
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
/**
* {@inheritDoc}
* @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for
* {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively
*/
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
System.out.println("@EnableAsync 的 mode 属性的值是 PROXY ");
// 从 ProxyAsyncConfiguration 这个类入手
return new String[] { ProxyAsyncConfiguration.class.getName() };
case ASPECTJ:
System.out.println("@EnableAsync 的 mode 属性的值是 ASPECTJ ");
// org.springframework.scheduling.aspectj.AspectJAsyncConfiguration
return new String[] { ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME };
default:
return null;
}
}
}
这个类的作用就是导入 AbstractAsyncConfiguration
的具体实现。
AbstractAsyncConfiguration
的实现主要有2个:ProxyAsyncConfiguration
和 AspectJAsyncConfiguration
而到底是导入哪一个,判断依据是 @EnableAsync
注解的 mode
属性。
如果 mode
等于 PROXY
,那导入的就是 ProxyAsyncConfiguration
;如果 mode
等于 ASPECTJ
,那导入的就是 AspectJAsyncConfiguration
我们重点研究 ProxyAsyncConfiguration
,这也是默认值,至于 AspectJAsyncConfiguration
,有兴趣可以自行深入研究。
在进入 ProxyAsyncConfiguration
的源码之前,先看下它的父类 AbstractAsyncConfiguration
package org.springframework.scheduling.annotation;
import java.util.Collection;
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* Abstract base {@code Configuration} class providing common structure for enabling
* Spring's asynchronous method execution capability.
*
* @author Chris Beams
* @author Stephane Nicoll
* @since 3.1
* @see EnableAsync
*/
@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableAsync;
@Nullable
protected Executor executor;
@Nullable
protected AsyncUncaughtExceptionHandler exceptionHandler;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
// 拿到 @EnableAsync 注解
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
if (this.enableAsync == null) {
System.out.println("类 " + importMetadata.getClassName() + " 上没有 @EnableAsync 注解");
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
/**
* Collect any {@link AsyncConfigurer} beans through autowiring.
*/
@Autowired(required = false)
void setConfigurers(Collection<AsyncConfigurer> 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();
}
}
先看其中的 setImportMetadata
方法,这个方法说白了就是解析 @EnableAsync
注解,解析完了存到成员变量里边供后面使用。
具体用啥,当然是用它的各种属性,比如 annotation
mode
proxyTargetClass
。
再看 setConfigurers
方法,这个主要就是通过解析你自定义的 AsyncConfigurer
来设置线程池、异常处理器。
通过代码我们也能看出,最多配置一个 AsyncConfigurer
,否则就报错了。可以自己验证下。
接下来看 ProxyAsyncConfiguration
的源码:
package org.springframework.scheduling.annotation;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.config.TaskManagementConfigUtils;
import org.springframework.util.Assert;
/**
* {@code @Configuration} class that registers the Spring infrastructure beans necessary
* to enable proxy-based asynchronous method execution.
*
* @author Chris Beams
* @author Stephane Nicoll
* @since 3.1
* @see EnableAsync
* @see AsyncConfigurationSelector
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
static {
System.out.println("研究 @EnableAsync @Async 就得从这个类入手");
System.out.println("这个类是一个配置类 @Configuration。会被 ConfigurationClassPostProcessor 处理。");
}
// bean 的名字是 org.springframework.context.annotation.internalAsyncAnnotationProcessor
@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");
System.out.println("重点是这个 new 出来的 AsyncAnnotationBeanPostProcessor");
System.out.println("重点是这个 new 出来的 AsyncAnnotationBeanPostProcessor");
System.out.println("重点是这个 new 出来的 AsyncAnnotationBeanPostProcessor");
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
// 解析 @EnableAsync 注解的 annotation 属性
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
System.out.println("设置执行器 ---> 一般都是线程池");
if (this.executor != null) {
bpp.setExecutor(this.executor);
}
System.out.println("设置异常处理器");
if (this.exceptionHandler != null) {
bpp.setExceptionHandler(this.exceptionHandler);
}
// 解析 @EnableAsync 注解的 proxyTargetClass 属性
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
// 解析 @EnableAsync 注解的 order 属性
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
return bpp;
}
}
这是一个配置类(被@Configuration标注了),里边就做了一个事儿:定义了一个类型为 AsyncAnnotationBeanPostProcessor
的bean。
首先 new 一个 AsyncAnnotationBeanPostProcessor
出来,然后解析 @EnableAsync
注解的 annotation
proxyTargetClass
order
属性。
拿到属性值后,赋值给 AsyncAnnotationBeanPostProcessor
。
有人可能会问 @EnableAsync
不是还有个 mode
属性么,为啥这里没用?别迷糊!能进入这个类的前提就是 @EnableAsync
的 mode
属性值是 PROXY
。
还有一点:定义的这个bean的名字是 org.springframework.context.annotation.internalAsyncAnnotationProcessor
。
从这个名字中的 internal 可以联想到,是不是可以自己定义一个 AsyncAnnotationBeanPostProcessor
来覆盖这个默认的?反正我是没试过,有兴趣可以试试。
最后,总结下:到这里,@EnableAsync 的各种属性就被传递给了 AsyncAnnotationBeanPostProcessor。后面的重点就转移到 AsyncAnnotationBeanPostProcessor 了。
多说一句,spring 中很多东西都是通过这 BeanPostProcessor
来实现的。所以这东西很重要。