【SpringBoot】@Async、AsyncConfigurer源码解析

前言

之前写过一篇@Async、@EnableAsync、@EnableScheduler、@Scheduled在Spring应用中的基本使用的文章。

最近在学习SpringBoot的异步任务,发现书中还提及到AsyncConfigurer接口,之前没见过它啊-_-! 那么 这个AsyncConfigurer接口到底有什么用?我们的异步执行器配置类要不要实现它? 带着疑惑,我就去阅读了一下相关的源码,终于找到答案了。

顺便还理清楚了另一个问题:Spring到底是如何决定某个目标方法使用哪个异步执行器(线程池)的?(提前透露:用户可以指定默认的异步执行器,若没指定,Spring会进行两次兜底,第二次兜底才是使用SimpleAsyncTaskExecutor)

注意:本文中大部分功能/源码都是Spring提供的,只有少数的是SpringBoot提供的(写有“SpringBoot”标识)。

主要流程

项目启动时

  • AsyncAnnotationBeanPostProcessor#setBeanFactory(BeanFactory beanFactory)

    • new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
      • AsyncAnnotationAdvisor#buildAdvice(executor, exceptionHandler);
        -AsyncExecutionAspectSupport#configure(Supplier<Executor> defaultExecutor, Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) // 注意传入的是Supplier,下面的代码不会马上执行
        - AsyncExecutionInterceptor#getDefaultExecutor(BeanFactory beanFactory)
        - AsyncExecutionAspectSupport#getDefaultExecutor(BeanFactory beanFactory)
        - new SimpleAsyncTaskExecutor()
  • 若容器中没有TaskExecutorBuilder类型的bean,SpringBoot会自动注册TaskExecutorBuilder
    TaskExecutionAutoConfiguration#taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator)

  • 若容器中没有Executor类型的bean,SpringBoot会自动注册ThreadPoolTaskExecutor
    TaskExecutionAutoConfiguration#applicationTaskExecutor(TaskExecutorBuilder builder)

  • 若容器中没有TaskSchedulerBuilder类型的bean,SpringBoot会自动注册TaskSchedulerBuilder
    TaskSchedulingAutoConfiguration#taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers)

  • 若容器中没有SchedulingConfigurer、TaskScheduler、ScheduledExecutorService类型的bean,SpringBoot会自动注册ThreadPoolTaskScheduler
    TaskSchedulingAutoConfiguration#taskScheduler(TaskSchedulerBuilder builder)

收到请求并执行有@Async的方法时

  • AsyncExecutionInterceptor#invoke(final MethodInvocation invocation)
    • AsyncExecutionAspectSupport#determineAsyncExecutor(Method method)
      • this.executors.get(method);
      • AnnotationAsyncExecutionInterceptor#getExecutorQualifier(Method method)
      • this.defaultExecutor.get();// 若方法上没有指定异步执行器,就执行上面的那个Supplier的get()方法,获取默认异步执行器
        • SingletonSupplier#get()
      • this.executors.put(method, executor);

主要流程中涉及到的类

AsyncAnnotationBeanPostProcessor

public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
	private Supplier<Executor> executor;

	private Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;

	@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;
	}
}

AsyncExecutionAspectSupport

public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {

	/**
	 * 默认异步执行器bean的默认beanName,当找到多个或0个TaskExecutor类型的bean时会用到它
	 */
	public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor";

	/**
	 * 确定目标方法的异步执行器
	 */
    protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
		// 先从缓存(Map<Method, AsyncTaskExecutor>)中找目标方法的异步执行器
		AsyncTaskExecutor executor = this.executors.get(method);
		// 若缓存中没有找到(第一次异步执行该方法)
		if (executor == null) {	
			Executor targetExecutor;
			// 先获取方法上指定的异步执行器
			String qualifier = getExecutorQualifier(method);
			if (StringUtils.hasLength(qualifier)) {
				targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
			}
			// 若方法上没有指定异步执行器,就调用项目启动时设置的那个Supplier,获取默认异步执行器(用户指定的默认异步执行器/Spring兜底的默认执行器)!!!
			else {
				targetExecutor = this.defaultExecutor.get();
			}
			if (targetExecutor == null) {
				return null;
			}
			executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
					(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
			// 将目标方法及其最终确定使用的异步执行器放入缓存中
			this.executors.put(method, executor);
		}
		return executor;
	}

	public void configure(Supplier<Executor> defaultExecutor, Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
		// 这里的Supplier:若用户没有指定默认执行器,就通过AsyncExecutionAspectSupport#getDefaultExecutor(this.beanFactory)获取Spring兜底的默认执行器
		// 但是实际传入的是AsyncExecutionAspectSuppor的子类AsyncExecutionInterceptor,故执行的是子类的getDefaultExecutor(beanFactory)方法
		this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
		this.exceptionHandler = new SingletonSupplier<>(exceptionHandler, SimpleAsyncUncaughtExceptionHandler::new);
	}

	/**
	 * 用户没有指定默认异步执行器时,获取兜底的默认执行器
	 */
	protected Executor getDefaultExecutor(BeanFactory beanFactory) {
		if (beanFactory != null) {
			try {
				// 从容器中找TaskExecutor类型的bean... 注意不是Executor,因为它也会与ScheduledExecutorService匹配,这对于我们的目的是不可用的。
				// 注意:SpringBoot的TaskExecutionAutoConfiguration、TaskSchedulingAutoConfiguration自动注册的ThreadPoolTaskExecutor、ThreadPoolTaskScheduler都是TaskExecutor的后代类。
				return beanFactory.getBean(TaskExecutor.class);
			} catch (NoUniqueBeanDefinitionException ex) {
				logger.debug("Could not find unique TaskExecutor bean", ex);
				try {
					// 如果查找到多个TaskExecutor类型的bean,就根据默认的beanName(即"taskExecutor")来筛选出一个
					return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
				}
				catch (NoSuchBeanDefinitionException ex2) {
					// 如果筛选失败,则返回null(注意:子类还会再兜底)
					if (logger.isInfoEnabled()) {
						logger.info("More than one TaskExecutor bean found within the context, and none is named " +
								"'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +
								"as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());
					}
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				logger.debug("Could not find default TaskExecutor bean", ex);
				try {
					// 如果查找到0个TaskExecutor类型的bean,就根据默认的beanName(即"taskExecutor")从容器中查找Executor类型的bean
					return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
				}
				catch (NoSuchBeanDefinitionException ex2) {
					// 如果还是查找不到,就返回null(注意:子类还会再兜底)
					logger.info("No task executor bean found for async processing: " +
							"no bean of type TaskExecutor and no bean named 'taskExecutor' either");
				}
				// Giving up -> either using local default executor or none at all...
			}
		}
		return null;
	}
}

AsyncExecutionInterceptor

public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {

	public Object invoke(final MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
		final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
		
		// 判定使用哪个异步执行器来执行目标方法
		AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
		if (executor == null) {
			throw new IllegalStateException(
					"No executor specified and no default executor set on AsyncExecutionInterceptor either");
		}

		Callable<Object> task = () -> {
			try {
				Object result = invocation.proceed();
				if (result instanceof Future) {
					return ((Future<?>) result).get();
				}
			}
			catch (ExecutionException ex) {
				handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
			}
			catch (Throwable ex) {
				handleError(ex, userDeclaredMethod, invocation.getArguments());
			}
			return null;
		};

		return doSubmit(task, executor, invocation.getMethod().getReturnType());
	}

	protected Executor getDefaultExecutor(BeanFactory beanFactory) {
		// 先调用父类(AsyncExecutionAspectSupport)的方法获取默认异步执行器
		Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
		// 若父类方法的返回值为null,则Spring再继续兜底:创建一个SimpleAsyncTaskExecutor
		// SimpleAsyncTaskExecutor:每次都会启动新的线程执行任务,并允许开发者控制并发线程的上限(concurrencyLimit),从而起到一定的资源节流作用。concurrencyLimit默认值为-1,即不启用资源节流。
		return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
	}
}

AnnotationAsyncExecutionInterceptor

public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionInterceptor {

    protected String getExecutorQualifier(Method method) {
		// Maintainer's note: changes made here should also be made in
		// AnnotationAsyncExecutionAspect#getExecutorQualifier
		Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
		if (async == null) {
			async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
		}
		// 返回目标方法上@Asyn注解的value属性值
		return (async != null ? async.value() : null);
	}
}

SingletonSupplier

public class SingletonSupplier<T> implements Supplier<T> {

	// 单例对象的指定提供者
	private final Supplier<? extends T> instanceSupplier;

	// 单例对象的兜底提供者(当指定提供者为null时,使用它)
	private final Supplier<? extends T> defaultSupplier;

	// 最终的单例对象
	private volatile T singletonInstance;

	public SingletonSupplier(@Nullable Supplier<? extends T> instanceSupplier, Supplier<? extends T> defaultSupplier) {
		this.instanceSupplier = instanceSupplier;
		this.defaultSupplier = defaultSupplier;
	}

	/**
	 * 获取单例对象的优先级:singletonInstance --> instanceSupplier --> defaultSupplier
	 */
	public T get() {
		// 先尝试直接获取singletonInstance
		T instance = this.singletonInstance;
		if (instance == null) {
			synchronized (this) {
				instance = this.singletonInstance;
				// 若singletonInstance为null
				if (instance == null) {
					// 若instanceSupplier不为null,就使用它来生产单例对象
					if (this.instanceSupplier != null) {
						instance = this.instanceSupplier.get();
					}
					// 若单例对象还为null且defaultSupplier不为null,就使用defaultSupplier来生产单例对象
					if (instance == null && this.defaultSupplier != null) {
						instance = this.defaultSupplier.get();
					}
					// 将生产出来的单例对象赋值给singletonInstance
					this.singletonInstance = instance;
				}
			}
		}
		return instance;
	}
}

TaskExecutionAutoConfiguration

@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
// 对应spring.task.execution
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {

	/**
	 * Bean name of the application {@link TaskExecutor}.
	 */
	public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";

	@Bean
	@ConditionalOnMissingBean
	public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
			ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
			ObjectProvider<TaskDecorator> taskDecorator) {
		TaskExecutionProperties.Pool pool = properties.getPool();
		TaskExecutorBuilder builder = new TaskExecutorBuilder();
		builder = builder.queueCapacity(pool.getQueueCapacity());
		builder = builder.corePoolSize(pool.getCoreSize());
		builder = builder.maxPoolSize(pool.getMaxSize());
		builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
		builder = builder.keepAlive(pool.getKeepAlive());
		Shutdown shutdown = properties.getShutdown();
		builder = builder.awaitTermination(shutdown.isAwaitTermination());
		builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
		builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
		builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
		builder = builder.taskDecorator(taskDecorator.getIfUnique());
		return builder;
	}

	@Lazy
	// 这里name属性值="applicationTaskExecutor","taskExecutor",正好AsyncExecutionAspectSupport#DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor"!!!
	// 所以若用户没有手动注册过Executor类型的bean,该方法就会执行,会自动注册一个ThreadPoolTaskExecutor,name="applicationTaskExecutor",alias="taskExecutor"
	// 那么AsyncExecutionAspectSupport一定能兜底成功(即默认异步执行器至少能使用到这个taskExecutor),那么它的子类AsyncExecutionInterceptor就不会后续兜底(即不会使用到SimpleAsyncTaskExecutor)!!!
	@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME, AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
	@ConditionalOnMissingBean(Executor.class)
	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
		return builder.build();
	}
}

TaskSchedulingAutoConfiguration

@ConditionalOnClass(ThreadPoolTaskScheduler.class)
@Configuration(proxyBeanMethods = false)
// 对应spring.task.scheduling
@EnableConfigurationProperties(TaskSchedulingProperties.class)
@AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
public class TaskSchedulingAutoConfiguration {

	@Bean
	@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
	@ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class })
	public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
		return builder.build();
	}

	@Bean
	@ConditionalOnMissingBean
	public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties,
			ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
		TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
		builder = builder.poolSize(properties.getPool().getSize());
		Shutdown shutdown = properties.getShutdown();
		builder = builder.awaitTermination(shutdown.isAwaitTermination());
		builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
		builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
		builder = builder.customizers(taskSchedulerCustomizers);
		return builder;
	}

}

流程图:

AsyncExecutionAspectSupport#determineAsyncExecutor()

在这里插入图片描述

AsyncExecutionAspectSupport#getDefaultExecutor()

在这里插入图片描述

总结:

各种情况下的默认异步执行器

  • 情况1.用户注册了AsyncConfigurer的实现类bean,并重写getAsyncExecutor(),即指定了默认异步执行器

    • 在第一次执行异步任务时Spring会自动调用实现类bean的getAsyncExecutor()获取到它,获取到后会赋值给最终的单例对象singletonInstance,并存入缓存Map<Method, AsyncTaskExecutor>中。
    • 注意:上面说了在第一次执行异步任务时Spring会自动调用注册的实现类bean的getAsyncExecutor()获取到它,所以getAsyncExecutor()方法上不需要添加@Bean注解
    • 注意:由于用户指定的默认异步执行器并不是Spring Bean,所以getAsyncExecutor()中必须手动执行ThreadPoolTaskExecutor#initialize(),否则会报错:ThreadPoolTaskExecutor not initialized
  • 情况2.用户没有注册过AsyncConfigurer的实现类,即没有指定默认异步执行器

    • 情况2-1.用户注册了1个TaskExecutor类型的bean
      那么AsyncExecutionAspectSupport兜底成功,使用该异步执行器

    • 情况2-2.用户注册了多个TaskExecutor类型的bean

      • 情况2-2-1.有一个的name = “taskExecutor”
        那么AsyncExecutionAspectSupport兜底成功,使用该异步执行器
      • 情况2-2-2.没有name = “taskExecutor”
        那么AsyncExecutionAspectSupport兜底失败(注意:子类AsyncExecutionInterceptor还会再兜底,就会使用到SimpleAsyncTaskExecutor
    • 情况2-3.用户注册了0个TaskExecutor类型的bean

      • 情况2-3-1.用户注册过类型为Executor,且name = “taskExecutor” 的bean
        那么AsyncExecutionAspectSupport兜底成功,使用该异步执行器

        补充:这样就没必要手动注册了,直接使用情况2-3-3,在application.yml中配置即可

      • 情况2-3-2.用户没有注册过类型为Executor,且name = “taskExecutor” 的bean
        那么AsyncExecutionAspectSupport兜底失败(注意:子类AsyncExecutionInterceptor还会再兜底,就会使用到SimpleAsyncTaskExecutor

      • 情况2-3-3.用户没有注册过Executor类型的bean
        那么SpringBoot会根据application.yml的配置自动注册一个ThreadPoolTaskExecutor,name=“applicationTaskExecutor”,alias=“taskExecutor”

        同理,若用户没有注册过SchedulingConfigurer、TaskScheduler和ScheduledExecutorService类型的bean,那么SpringBoot会根据application.yml的配置自动注册ThreadPoolTaskScheduler

        那么AsyncExecutionAspectSupport一定能兜底成功(即默认异步执行器至少能使用到这个自动注册的taskExecutor),那么它的子类AsyncExecutionInterceptor就不会再兜底,就不会使用到SimpleAsyncTaskExecutor

    • 总之分很多种情况,不同情况下兜底的默认异步执行器的结果都不一样。

    • 建议:尽量不要使用到子类AsyncExecutionInterceptor的再兜底,也就是不要使用到SimpleAsyncTaskExecutor,因为它不是一个好的异步执行器~

几种配置异步执行器的方式比较

方式优点缺点
SpringBoot自动注册ThreadPoolTaskExecutor很简单,只需要在配置文件中配置即可只支持简单配置,对于高级配置,请考虑使用TaskExecutorCustomizer
手动注册ThreadPoolTaskExecutor支持复杂配置无法配置UncaughtExceptionHandler(见java.lang.Thread#uncaughtExceptionHandler,java.lang.Thread#defaultUncaughtExceptionHandler,java.lang.ThreadGroup#uncaughtException
手动注册AsyncConfigure-bean,实现getExecutor()方法可以配置AsyncUncaughtExceptionHandler(见org.springframework.scheduling.annotation.AsyncConfigurer#getAsyncUncaughtExceptionHandler),处理void返回类型的异步方法执行期间引发的异常只能供@Async使用,并没有往容器中注册ThreadPoolTaskExecutor-bean
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值