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

发布于:2025-04-20 ⋅ 阅读:(38) ⋅ 点赞:(0)

从本文开始,就正式进入源码追踪阶段了,上一篇的最后我们提到了 @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个: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 {

	@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 属性么,为啥这里没用?别迷糊!能进入这个类的前提就是 @EnableAsyncmode 属性值是 PROXY
还有一点:定义的这个bean的名字是 org.springframework.context.annotation.internalAsyncAnnotationProcessor
从这个名字中的 internal 可以联想到,是不是可以自己定义一个 AsyncAnnotationBeanPostProcessor 来覆盖这个默认的?反正我是没试过,有兴趣可以试试。

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

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


网站公告

今日签到

点亮在社区的每一天
去签到