目錄
2. ProxyAsyncConfiguration異步代理配置類
3. AsyncAnnotationBeanPostProcessor
在項目開發中,基於業務邏輯合理性以及程序執行性能等方面的考慮,程序執行異步化是一個很好地選擇;當然,異步化的方式有很多種,包括自定義線程池、Guava開源組件AsyncEventBus、以及spring內部支持的@Async註解方式等等,這裏,我們主要分析下spring對異步化的支持@EnableAsync&@Async的源碼實現;
1. @EnableAsync開啓異步化支持
通過@EnableAsync的註解名稱很容易得知,這又是一個enable*的實現模式,類似於介紹aop時@EnableAspectJAutoProxy開啓aspectj切面的支持,介紹spring聲明式事務時@EnableTransactionManager開啓聲明式事務支持一樣;下面首先看一下@EnableAsync的源碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
/**
* Indicate the 'async' annotation type to be detected at either class
* or method level.
* <p>By default, both Spring's @{@link Async} annotation and the EJB 3.1
* {@code @javax.ejb.Asynchronous} annotation will be detected.
* <p>This attribute exists so that developers can provide their own
* custom annotation type to indicate that a method (or all methods of
* a given class) should be invoked asynchronously.
*/
Class<? extends Annotation> annotation() default Annotation.class;
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies.
* <p><strong>Applicable only if the {@link #mode} is set to {@link AdviceMode#PROXY}</strong>.
* <p>The default is {@code false}.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Async}.
* For example, other beans marked with Spring's {@code @Transactional} annotation
* will be upgraded to subclass proxying at the same time. This approach has no
* negative impact in practice unless one is explicitly expecting one type of proxy
* vs. another — for example, in tests.
*/
boolean proxyTargetClass() default false;
/**
* Indicate how async advice should be applied.
* <p><b>The default is {@link AdviceMode#PROXY}.</b>
* Please note that proxy mode allows for interception of calls through the proxy
* only. Local calls within the same class cannot get intercepted that way; an
* {@link Async} annotation on such a method within a local call will be ignored
* since Spring's interceptor does not even kick in for such a runtime scenario.
* For a more advanced mode of interception, consider switching this to
* {@link AdviceMode#ASPECTJ}.
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the order in which the {@link AsyncAnnotationBeanPostProcessor}
* should be applied.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run
* after all other post-processors, so that it can add an advisor to
* existing proxies rather than double-proxy.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
上面的幾個屬性通過註釋都能很好地理解,多個字段的含義和我麼在分析聲明式事務時基本是一致的,我們主要看一下Import註解導入的AsyncConfigurationSelector的原理;
AsyncConfigurationSelector繼承結構如下,可以看出它是一個ImportSelector,用來導入其它的配置類
AsyncConfigurationSelector的實現源碼如下,可以看出根據不同的代理模式adviceMode,這裏導入了不同的配置類,PROXY代理時,導入了ProxyAsyncConfiguration類,下面主要對該類進行分析;
/**
* 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
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;
}
}
}
2. ProxyAsyncConfiguration異步代理配置類
ProxyAsyncConfiguration配置類的繼承結構以及源碼如下,可以看出父類AbstractAsyncConfiguration也是一個配置類;
/**
* {@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 {
@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;
}
}
ProxyAsyncConfiguration的源碼比較簡單,通過在父類AbstractAsyncConfiguration中解析到的enableAsync註解,構造了AsyncAnnotationBeanPostProcessor,並進行了bean化,後面再進一步展開分析;
enableAsync註解是在父類AbstractAsyncConfiguration初始化的,下面看一下該註解的初始化過程:
/**
* 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 {
protected AnnotationAttributes enableAsync;
protected Executor executor;
protected AsyncUncaughtExceptionHandler exceptionHandler;
@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());
}
}
/**
* 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();
}
}
由上,可以看出,
- 該配置類通過實現ImportAware接口,在接口方法setImportMetadata中完成了enableAsync的解析;
- 方法setConfigurers通過自動注入的方式獲取容器中AsyncConfigurer的實現類,分別獲取了執行器和異常處理器;
AbstractAsyncConfiguration中構造完成的成員變量都在ProxyAsyncConfiguration中,用於完成AsyncAnnotationBeanPostProcessor的創建,下面單獨分析下AsyncAnnotationBeanPostProcessor的實現原理;
3. AsyncAnnotationBeanPostProcessor
首先看一下AsyncAnnotationBeanPostProcessor整體的實現結構:
由繼承結構可以看出,AsyncAnnotationBeanPostProcessor是一個Bean後處理器,同時實現了BeanFactoryAware接口,下面分別分析下這兩個接口的實現邏輯;
3.1 BeanFactoryAware實現邏輯
BeanFactoryAware接口是由AbstractBeanFactoryAwareAdvisingPostProcessor直接實現的,同時AsyncAnnotationBeanPostProcessor對該接口方法進行了覆蓋,首先看下這兩個方法的具體實現:
//AsyncAnnotationBeanPostProcessor實現如下:
@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;
}
//AbstractBeanFactoryAwareAdvisingPostProcessor實現如下:
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory ?
(ConfigurableListableBeanFactory) beanFactory : null);
}
在AsyncAnnotationBeanPostProcessor的實現中,這裏實例化了一個異步註解切面AsyncAnnotationAdvisor,最後賦值到了成員變量advisor上面,後面在bean後處理器中會應用該切面;
在實例化異步切面AsyncAnnotationAdvisor時,主要完成了切點和增強的構造,如下:
/**
* Create a new {@code AsyncAnnotationAdvisor} for the given task executor.
* @param executor the task executor to use for asynchronous methods
* (can be {@code null} to trigger default executor resolution)
* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use to
* handle unexpected exception thrown by asynchronous method executions
* @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
*/
@SuppressWarnings("unchecked")
public AsyncAnnotationAdvisor(Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(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.
}
if (exceptionHandler != null) {
this.exceptionHandler = exceptionHandler;
}
else {
this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
}
this.advice = buildAdvice(executor, this.exceptionHandler);
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
爲了更深入的理解切面的實現邏輯,這裏再分別對切點和增強進行展開說明
3.1.1 異步註解增強/攔截器AnnotationAsyncExecutionInterceptor的原理
繼承類圖如下:
由此可見,AnnotationAsyncExecutionInterceptor是一個方法攔截器,
3.1.2
3.2 BeanPostProcessor後處理器實現邏輯
bean後處理的接口實現是在抽象父類AbstractAdvisingBeanPostProcessor中完成的,如下:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
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);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No async proxy needed.
return bean;
}