@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

相關文章
相關標籤/搜索