欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > @EnableAsync+@Async源码学习笔记之二

@EnableAsync+@Async源码学习笔记之二

2025/4/21 3:56:24 来源:https://blog.csdn.net/qq_17586821/article/details/147350444  浏览:    关键词:@EnableAsync+@Async源码学习笔记之二

从本文开始,就正式进入源码追踪阶段了,上一篇的最后我们提到了 @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个:ProxyAsyncConfigurationAspectJAsyncConfiguration
而到底是导入哪一个,判断依据是 @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 属性么,为啥这里没用?别迷糊!能进入这个类的前提就是 @EnableAsyncmode 属性值是 PROXY
还有一点:定义的这个bean的名字是 org.springframework.context.annotation.internalAsyncAnnotationProcessor
从这个名字中的 internal 可以联想到,是不是可以自己定义一个 AsyncAnnotationBeanPostProcessor 来覆盖这个默认的?反正我是没试过,有兴趣可以试试。

最后,总结下:到这里,@EnableAsync 的各种属性就被传递给了 AsyncAnnotationBeanPostProcessor。后面的重点就转移到 AsyncAnnotationBeanPostProcessor 了。

多说一句,spring 中很多东西都是通过这 BeanPostProcessor 来实现的。所以这东西很重要。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词