目录
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;
}