从本文开始,就正式进入源码追踪阶段了,上一篇的最后我们提到了 @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@Nullablepublic 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.AspectJAsyncConfigurationreturn 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 {@Nullableprotected AnnotationAttributes enableAsync;@Nullableprotected Executor executor;@Nullableprotected AsyncUncaughtExceptionHandler exceptionHandler;@Overridepublic 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
来实现的。所以这东西很重要。