Spring 之 @Async 的简单使用与源码解析

@Async 案例演示

有时候需我们需要让一个方法异步执行,但是又不想自己去写异步代码,毕竟和业务不相关。所以 Spring 就非常友好,提供 @Async 注解让方法异步执行。

想要让 @Async 注解生效,必须通过 @EnableAsync 注解来激活这个功能。代码如下:

@Component
public class Person {

	@Async
	public void show(String name) {
		System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName());
		System.out.println("======>show...");
	}
}

@ComponentScan
@EnableAsync
public class AopProxyTest {
	public static void main(String[] args) {
		System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName());
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopProxyTest.class);

		Person bean = context.getBean(Person.class);

		bean.show("abc");
	}
}

测试结果如下:

Thread.currentThread().getName() = main
Thread.currentThread().getName() = SimpleAsyncTaskExecutor-1
======>show...

从打印结果中可看出两个 show() 方法时被在 SimpleAsyncTaskExecutor-1 线程中执行的,并不是在 main() 线程中。说明 @Async 已经生效。

@Async 源码分析

首先想要让 @Async 功能生效,必须通过 @EnableAsync 注解才能激活,因为在 @EnableAsync 注解中会通过 @Import 注解导入该功能相关类,源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

}

AsyncConfigurationSelector 类源码如下:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	@Override
	@Nullable
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

看到 selectImports() 方法中,导入了 ProxyAsyncConfiguration 类,重点关注这个类就行,所有的核心类都是通过这配置类导入的, ProxyAsyncConfiguration 类源码如下:

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor() {

		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();

		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}
}

然后重点看到这个 AsyncAnnotationBeanPostProcessor 类,很明显又是 Spring BeanPostProcessor 接口的应用,但是这个类比较特殊,因为它并没有像事务、@Aspect 等传统型切面一样去实现 AbstractAutoProxyzCreator 抽象类。这个类自己搞特殊借助 BeanPostProcessor 接口做扩展。所以你只需要关注 BeanPostProcessor 接口中的方法即可。

这里还要注意的是该类还是实现了 BeanFactoryAware 接口,那么必然要关注该接口的方法 setBeanFactory()。

进入 AsyncAnnotationBeanPostProcessor 类,核心源码如下:

public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {

	@Nullable
	private Supplier<Executor> executor;

	public AsyncAnnotationBeanPostProcessor() {
		setBeforeExistingAdvisors(true);
	}

	public void setExecutor(Executor executor) {
		this.executor = SingletonSupplier.of(executor);
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		/**
		 * 在这里 new 一个 Advisor AsyncAnnotationAdvisor 专门用来处理 @Async 注解的增强器
		 */
		AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
		if (this.asyncAnnotationType != null) {
			advisor.setAsyncAnnotationType(this.asyncAnnotationType);
		}
		advisor.setBeanFactory(beanFactory);
		this.advisor = advisor;
	}

}

AsyncAnnotationBeanPostProcessor 类构造方法中会设置 beforeExistingAdvisors 属性为 true,然后在看到 setBeanFactory() 方法。再解释这个方法之前先回忆下,要定义切面,肯定要有 Advisor、而 Advisor 必然包含 Advice 和 Pointcut,而 Pointcut 必然包含 ClassFilter、MethodMatcher 匹配器。这是 Spring 切面耳熟能详的一套框架。所以在看到 setBeanFactory() 方法中,提供了 AsyncAnnotationAdvisor,并且注意该类中有个 executor 线程执行器。

进入 AsyncAnnotationAdvisor 类,核心源码如下:

public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

	private Advice advice;

	private Pointcut pointcut;

	public AsyncAnnotationAdvisor(
			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

		Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
		asyncAnnotationTypes.add(Async.class);
		try {
			asyncAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			// If EJB 3.1 API not present, simply ignore.
		}
		this.advice = buildAdvice(executor, exceptionHandler);
		this.pointcut = buildPointcut(asyncAnnotationTypes);
	}
}

从上述代码中可以看到就是要去构建 Advice + Pointcut,进入 buildAdvice() 源码如下:

	protected Advice buildAdvice(
			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

		/**
		 * 在在这里生成 Advice AnnotationAsyncExecutionInterceptor 专门用来处理 @Async 注解
		 */
		AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
		interceptor.configure(executor, exceptionHandler);
		return interceptor;
	}

这里就是在创建一个 Adivce,类型是 AnnotationAsyncExecutionInterceptor,而且这个 Advice 持有 executor 线程执行器。这里创建的拦截器在目标方法调用时,就会进入此 Advice 执行 @Async 逻辑。这个是 Spring 代理的基本调用流程。这里不过多赘述。

然后进入 buildPointcut() 方法,核心源码如下:

	protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
		ComposablePointcut result = null;
		for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
			/**
			 * new 了一个 AnnotationMatchingPointcut 对象 专门用来处理 @Async 注解的
			 */
			Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
			Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);
			if (result == null) {
				result = new ComposablePointcut(cpc);
			}
			else {
				result.union(cpc);
			}
			result = result.union(mpc);
		}
		return (result != null ? result : Pointcut.TRUE);
	}

这里定义了两个 Pointcut 联合之后,会对类或者方法进行匹配,匹配是否有 @Async 注解修饰,有的话就会生成代理对象。

看到第一个 AnnotationMatchingPointcut,然后查看它的 matches() 匹配逻辑,源码如下:

	public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) {
		this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);
		this.methodMatcher = MethodMatcher.TRUE;
	}

首先看到 this.methodMatcher = MethodMatcher.TRUE 代码,表示该 Pointcut 不对方法做检验,进入 AnnotationClassFilter 类的 matches() 方法,核心源码如下:

	@Override
	public boolean matches(Class<?> clazz) {
		return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(clazz, this.annotationType) :
				clazz.isAnnotationPresent(this.annotationType));
	}

这个方法表示类上面是否有 @Async 注解修饰。

进入第二个 AnnotationMatchingPointcut,然后查看它的 matches() 匹配逻辑,核心源码如下:

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (matchesMethod(method)) {
			return true;
		}
		// Proxy classes never have annotations on their redeclared methods.
		if (Proxy.isProxyClass(targetClass)) {
			return false;
		}
		// The method may be on an interface, so let's check on the target class as well.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		return (specificMethod != method && matchesMethod(specificMethod));
	}

	private boolean matchesMethod(Method method) {
		return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
				method.isAnnotationPresent(this.annotationType));
	}

可以看出就是判断这个方法上是否有 @Async 注解修饰,如果有就会创建代理对象。okay,现在 Advisor 创建好了,那么就要去看看在哪里创建代理对象的。

在回到 AsyncAnnotationBeanPostProcessor 类,它实现了 BeanPostProcessor 接口,所以关注这个接口提供的方法,源码如下:

	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

postProcessBeforeInitialization() 方法并没有做任何事情,略过。继续看到另外的方法,源码如下:

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (this.advisor == null || bean instanceof AopInfrastructureBean) {
			return bean;
		}

		if (bean instanceof Advised) {
			Advised advised = (Advised) bean;
			if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return bean;
			}
		}

		if (isEligible(bean, beanName)) {
			ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
			if (!proxyFactory.isProxyTargetClass()) {
				evaluateProxyInterfaces(bean.getClass(), proxyFactory);
			}
			proxyFactory.addAdvisor(this.advisor);

			return proxyFactory.getProxy(classLoader);
		}

从上述代码一眼就可以看到 getProxy() 方法,明显就是在这里去创建代理对象的。现在对上述代码拆分讲解

先看到下面这段逻辑,判断代码如下:

	if (this.advisor == null || bean instanceof AopInfrastructureBean) {
		return bean;
	}

因为刚才在 setBeanFactory() 方法中就已经设置了 AsyncAnnotationAdvisor,所以这里的 advisor 不为 null,现在只有 Person 类中的 show() 方法加了 @Async 注解,也就是说只有 Person 才会创建代理对象。假设现在的 bean 是 Person 实例,是个普通类型,并不是 AopInfrastructureBean,所以就不会走 return。只有实现了 AopInfrastructureBean 接口的 bean 才会走 return 表示不需要创建代理,就比如 AsyncAnnotationBeanPostProcessor 类就实现了 AopInfrastructureBean 接口,表示此类不需要创建代理,很明显肯定不用创建代理,如果这个类都要创建代理岂不是乱套了。所以 Spring 这个判断拦截非常细节。

然后再看到这段逻辑,代码如下:

	if (bean instanceof Advised) {
		Advised advised = (Advised) bean;
		if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
			if (this.beforeExistingAdvisors) {
				advised.addAdvisor(0, this.advisor);
			}
			else {
				advised.addAdvisor(this.advisor);
			}
			return bean;
		}
	}

什么时候的 bean 才会和 Advised 属于同一个类型呢?那就是已经经过了代理的对象。这种情况那就是存在很多切面,比如 @Aspect、@Async 注解同时修饰在 show() 方法上,@Aspect 注解生效会通过 @EnableAspectJAutoProxy 注解激活该功能会导入 AnnotationAwareAspectJAutoProxyCreator,而该类也是 BeanPostProcessor 接口应用,前面已经知道 @Async 激活也是通过 AsyncAnnotationBeanPostProcessor 类,也是一个 BeanPostProcessor 接口应用,那么现在问题来了,这两个类同时存在,并且都是 BeanPostProcessor 接口类型,而且都具备创建代理对象的功能。在 show() 方法上也标注 @Around、@Async 两个注解,你认为会不会创建两个代理对象呢?

答案是不会的,AnnotationAwareAspectJAutoProxyCreatorAsyncAnnotationBeanPostProcessor 的优先级决定用哪个类去创建代理对象。而 AnnotationAwareAspectJAutoProxyCreator 类的优先级是高于后者的。所以这两个类同时存在时,使用 AnnotationAwareAspectJAutoProxyCreator 类创建代理对象。然后再看到上面那段判断逻辑。bean(假设是 Person 实例) 此时被 AnnotationAwareAspectJAutoProxyCreator 类创建代理对象,属于 Advised 对象。

然后再调用 isEligible() 方法取判断当前的 bean 是否能使用 AsyncAnnotationAdvisor 增强。答案是可以的,因为在 show() 方法上有 @Async 注解,前面的创建的 ClassFilter、MethodMatcher 匹配器会匹配到 @Async 注解。

然后再看到 this.beforeExistingAdvisors() 方法,在前面就已经说过再 AsyncAnnotationBeanPostProcessor 类构造方法中就已设置为 true ,所以这成立。就把 AsyncAnnotationAdvisor 切面加入到 Advised 集合中,而且还是在第一位置,也就表示在调用目标方法时,首先会给你开启线程异步执行 show() 方法,如果存在事务传播就要格外格外注意,这一点不做过多扩展。此时代理对象中就有 AnnotationAwareAspectJAutoProxyCreator 类 Advice,也有 AsyncAnnotationBeanPostProcessor 类 Advice,所以在调用目标方法时就会执行所有 Advice。但是代理对象始终只有一个,也只被创建过一次。

然后再看到最后一段逻辑,代码如下:

	if (isEligible(bean, beanName)) {
		ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
		if (!proxyFactory.isProxyTargetClass()) {
			evaluateProxyInterfaces(bean.getClass(), proxyFactory);
		}
		proxyFactory.addAdvisor(this.advisor);

		return proxyFactory.getProxy(classLoader);
	}

isEligible() 方法成立,因为 Person#show() 方法有 @Async 注解修饰,然后就开始调用 proxyFactory.getProxy() 创建代理对象,这里需要注意 evaluateProxyInterfaces() 方法会去计算使用 cglib、还是 jdk 动态代理。ProxyFactory 是动态代理过程中的一个上下文对象,封装着调用过程中需要的内容,比如所有的 Advisors,目标对象等等。

至此 AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization() 就完成了,代理对象也创建成功!接下来就是调用的过程。

在调用目标方法 show() 时,会触发到切面逻辑,这里使用的是 cglib,因为没有接口,核心源码如下:

	private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

		private final AdvisedSupport advised;

		public DynamicAdvisedInterceptor(AdvisedSupport advised) {
			this.advised = advised;
		}

		@Override
		@Nullable
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					// 王者: 是否有需要暴露这个代理对象,使用 ThreadLocal 让线程之间共享这个代理对象(异步事务)
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;

				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {
					// We need to create a method invocation...
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

getInterceptorsAndDynamicInterceptionAdvice() 方法会获取到所有的 Advisor,这里假设就只有一个 @Async 注解,那么会有 AsyncAnnotationAdvisor 增强器。

然后进入到 AsyncAnnotationAdvisor 中封装的 Advice,也就是 AnnotationAsyncExecutionInterceptor 类,核心源码如下:

	@Override
	@Nullable
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		System.out.println(invocation.getMethod().getName()+"------>async 拦截器被调用.....");
		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);

		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());
	}

通过 determineAsyncExecutor() 方法获取到线程执行器,然后进入 doSubmit() 方法,代码如下:

	@Nullable
	protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
		if (CompletableFuture.class.isAssignableFrom(returnType)) {
			return CompletableFuture.supplyAsync(() -> {
				try {
					return task.call();
				}
				catch (Throwable ex) {
					throw new CompletionException(ex);
				}
			}, executor);
		}
		else if (ListenableFuture.class.isAssignableFrom(returnType)) {
			return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
		}
		else if (Future.class.isAssignableFrom(returnType)) {
			return executor.submit(task);
		}
		else {
			executor.submit(task);
			return null;
		}
	}

show() 方法返回值不属于 CompletableFutureListenableFutureFuture ,所以直接就提交给线程池执行,task 对象中通过 invocation.proceed() 调用到目标方法逻辑。所以 Spring 就是这样执行 @Async 流程的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔道不误砍柴功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值