@Async - spring的AOP实现

spring会根据定义的AdviceMode类型(PROXY, ASPECTJ)选择不一样的aop实现方式, 通常使用的是PROXY 。java

SpringBoot当要使用@Async时,需启动类显示声明@EnableAsync 来 注入 AsyncConfigurationSelectorAdviceModeImportSelector的扩展实现);spring

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

	/**
	 * @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 org.springframework.context.annotation.AdviceMode.PROXY:
				return new String[] { ProxyAsyncConfiguration.class.getName() };
			case org.springframework.context.annotation.AdviceMode.ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME };
			default:
				return null;
		}
	}
}

默认是AdviceMode.PROXY, 因此选择ProxyAsyncConfiguration, 初始化AsyncAnnotationBeanPostProcessor,含成员变量Advisorc#

// AbstractAsyncConfiguration
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableAsync = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
		if (this.enableAsync == null) {
			throw new IllegalArgumentException(
					"@EnableAsync is not present on importing class " + importMetadata.getClassName());
		}
	}

// ProxyAsyncConfiguration extends AbstractAsyncConfiguration
	@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");
		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		if (this.executor != null) {
			bpp.setExecutor(this.executor);
		}
		if (this.exceptionHandler != null) {
			bpp.setExceptionHandler(this.exceptionHandler);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}

AsyncAnnotationBeanPostProcessor 继承了 BeanFactoryAware 接口。在setBeanFactory方法中,初始化了AsyncAnnotationAdvisor !这就比较熟悉了。异步

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

PS@EnableAsync  能够经过设置属性 annotation 来指定自定义注解类型 。async

ProxyAsyncConfiguration构建AsyncAnnotationBeanPostProcessor时这个参数值被注入到其内部属性AsyncAnnotationType,并在 setBeanFactory 方法中被注入进AsyncAnnotationAdvisoride

AsyncAnnotationAdvisor

在具体的构造函数中 绑定了advice (AnnotationAsyncExecutionInterceptor )与pointcut(ComposablePointcut), 并指定切面注解类型是@Async函数

(在自定义advisor 时, advice与 pointcut 是advisor内共享成员变量)post

AnnotationAsyncExecutionInterceptor

extends AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptorui

由MethodInterceptor的定义可见: MethodInterceptor就是所谓的Advicethis

public interface Interceptor extends Advice {}

public interface MethodInterceptor extends Interceptor {
	
	/**
	 * Implement this method to perform extra treatments before and
	 * after the invocation. Polite implementations would certainly
	 * like to invoke {@link Joinpoint#proceed()}.
	 * @param invocation the method invocation joinpoint
	 * @return the result of the call to {@link Joinpoint#proceed()};
	 * might be intercepted by the interceptor
	 * @throws Throwable if the interceptors or the target object
	 * throws an exception
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;

}

AsyncExecutionAspectSupport.invoke 就是指定切面在命中时具体处理逻辑。

比较重要的是如何选择异步处理的线程池AsyncTaskExecutor过程 determineAsyncExecutor方法:

优先获取方法或方法所在类 配置的@Async指定的异步处理线程池对象名,在beanFactory中匹配线程次实例。

其次则是在初始化AnnotationAsyncExecutionInterceptor时从BeanFactory获取的 TaskExecutor.class类型对象。

ComposablePointcut

单个pointcut由MethodMatcher (方法匹配)与 ClassFilter (类匹配)组合构成。

public interface Pointcut {

	ClassFilter getClassFilter();

	MethodMatcher getMethodMatcher();

	/**
	 * Canonical Pointcut instance that always matches.
	 */
	Pointcut TRUE = TruePointcut.INSTANCE;
}

经常使用的有

  • AnnotationMatchingPointcut 针对于指定的类上注解、方法上注解 。依不一样构造方法的入参来指定注解类型
  • 抽象类 StaticMethodMatcherPointcut  的 具体实现 AnnotationClassOrMethodPointcut :   与AnnotationMatchingPointcut  用法大致一致。只针对于同一个注解来断定方法或类。
  • AspectJExpressionPointcut 主要针对于AspectJ的语法解析
  • ComposablePointcut 多个pointcut、 ClassFilter、 MethodMatcher的组合用法。 能够(intersection 交集 或  union  并集)

如下是spring针对Async构建的ComposablePointcut ,是由2个AnnotationMatchingPointcut 取并集而成。这也佐证了对于类及方法上的@Async都有效

protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
		ComposablePointcut result = null;
		for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
			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);
	}

那是何时执行条件过滤呢?

执行过程

回到AsyncAnnotationBeanPostProcessor,不单单继承BeanFactoryAware, 并且还实现了BeanPostProcessor接口!

在执行postProcessAfterInitialization方法内, 经过isEligible 方法对bean进行断定是否须要代理:会优先经过Pointcut的ClassFilter进行断定, 其次是MethodMatcher!

最终也是经过AopProxy.getProxy() 构建代理对象。AopProxy由ProxyCreatorSupport的createAopProxy()方法提供实例

p

相关文章
相关标签/搜索