Spring boot @EnableAsync与@Async源码分析

目录

1. @EnableAsync开启异步化支持

2. ProxyAsyncConfiguration异步代理配置类

3. AsyncAnnotationBeanPostProcessor

3.1 BeanFactoryAware实现逻辑

3.1.1 异步注解增强/拦截器AnnotationAsyncExecutionInterceptor的原理

3.1.2 切点AnnotationMatchingPointcut的执行逻辑

3.2 BeanPostProcessor后处理器实现逻辑

在项目开发中,基于业务逻辑合理性以及程序执行性能等方面的考虑,程序执行异步化是一个很好地选择;当然,异步化的方式有很多种,包括自定义线程池、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.
   * 

By default, both Spring's @{@link Async} annotation and the EJB 3.1    * {@code @javax.ejb.Asynchronous} annotation will be detected.    * 

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 annotation() default Annotation.class;   /**    * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed    * to standard Java interface-based proxies.    * 

Applicable only if the {@link #mode} is set to {@link AdviceMode#PROXY}.    * 

The default is {@code false}.    * 

Note that setting this attribute to {@code true} will affect all    * 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.    * 

The default is {@link AdviceMode#PROXY}.    * 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.    * 

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,用来导入其它的配置类

Spring boot @EnableAsync与@Async源码分析_第1张图片

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 {
 
  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也是一个配置类;

Spring boot @EnableAsync与@Async源码分析_第2张图片

/**
 * {@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 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.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 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整体的实现结构:

Spring boot @EnableAsync与@Async源码分析_第3张图片

由继承结构可以看出,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> asyncAnnotationTypes = new LinkedHashSet>(2);
    asyncAnnotationTypes.add(Async.class);
    try {
      asyncAnnotationTypes.add((Class)
      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是在buildAdvice方法中完成构造的,如下:

protected Advice buildAdvice(Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
    return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
  }

其具体继承类图如下:

Spring boot @EnableAsync与@Async源码分析_第4张图片

由此可见,AnnotationAsyncExecutionInterceptor是一个方法拦截器,其中接口MethodInterceptor的接口方式是在AsyncExecutionInterceptor中实现的,完成拦截逻辑的处理,如下:

/**
   * Intercept the given method invocation, submit the actual calling of the method to
   * the correct task executor and return immediately to the caller.
   * @param invocation the method to intercept and make asynchronous
   * @return {@link Future} if the original method returns {@code Future}; {@code null}
   * otherwise.
   */
  @Override
  public Object invoke(final MethodInvocation invocation) throws Throwable {
    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);


    if (executor == null) {
      throw new IllegalStateException(
          "No executor specified and no default executor set on AsyncExecutionInterceptor either");
    }
    
    Callable task = new Callable() {
      @Override
      public Object call() throws Exception {
        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方法完成异步执行器executor的初始化,具体过程如下:

在解析异步执行器时,首先是根据@Async注解的value属性查找对应的标识符以及类型为Executor的自定义异步执行器,

当没有找到时,获取defaultExecutor,也及在AbstractAsyncConfiguration中通过自动注入AsyncConfigurer实现类指定的执行器;

当没有AsyncConfigurer实现类指定执行器时,会继续尝试获取bean容器中TaskExecutor类型的自定义任务执行器,以及beanName为taskExecutor,类型为Executor的执行器;

当上述几种方式都获取不到时,默认会new一个SimpleAsyncTaskExecutor,每次执行被注解方法时,单独创建一个Thread来执行

这部分的实现源码如下:

/**
   * Determine the specific executor to use when executing the given method.
   * Should preferably return an {@link AsyncListenableTaskExecutor} implementation.
   * @return the executor to use (or {@code null}, but just if no default executor is available)
   */
  protected AsyncTaskExecutor determineAsyncExecutor(Method method) {


    AsyncTaskExecutor executor = this.executors.get(method);
    if (executor == null) {
      Executor targetExecutor;
      String qualifier = getExecutorQualifier(method);
      if (StringUtils.hasLength(qualifier)) {
        targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
      }
      else {
        targetExecutor = this.defaultExecutor;
        if (targetExecutor == null) {
          synchronized (this.executors) {
            if (this.defaultExecutor == null) {
              this.defaultExecutor = getDefaultExecutor(this.beanFactory);
            }
            targetExecutor = this.defaultExecutor;
          }
        }
      }
      if (targetExecutor == null) {
        return null;
      }
      executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
          (AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
      this.executors.put(method, executor);
    }


    return executor;
  }




/**
   * This implementation searches for a unique {@link org.springframework.core.task.TaskExecutor}
   * bean in the context, or for an {@link Executor} bean named "taskExecutor" otherwise.
   * If neither of the two is resolvable (e.g. if no {@code BeanFactory} was configured at all),
   * this implementation falls back to a newly created {@link SimpleAsyncTaskExecutor} instance
   * for local use if no default could be found.
   * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
   */
  @Override
  protected Executor getDefaultExecutor(BeanFactory beanFactory) {
    Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
    return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
  }
  
/**
   * Retrieve or build a default executor for this advice instance.
   * An executor returned from here will be cached for further use.
   * 

The default implementation searches for a unique {@link TaskExecutor} bean    * in the context, or for an {@link Executor} bean named "taskExecutor" otherwise.    * If neither of the two is resolvable, this implementation will return {@code null}.    * @param beanFactory the BeanFactory to use for a default executor lookup    * @return the default executor, or {@code null} if none available    * @since 4.2.6    * @see #findQualifiedExecutor(BeanFactory, String)    * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME    */ protected Executor getDefaultExecutor(BeanFactory beanFactory) {     if (beanFactory != null) {       try {         // Search for TaskExecutor bean... not plain Executor since that would         // match with ScheduledExecutorService as well, which is unusable for         // our purposes here. TaskExecutor is more clearly designed for it.         return beanFactory.getBean(TaskExecutor.class);       }       catch (NoUniqueBeanDefinitionException ex) {         logger.debug("Could not find unique TaskExecutor bean", ex);         try {           return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);         }         catch (NoSuchBeanDefinitionException ex2) {           if (logger.isInfoEnabled()) {             logger.info("More than one TaskExecutor bean found within the context, and none is named " +                 "'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +                 "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());           }         }       }       catch (NoSuchBeanDefinitionException ex) {         logger.debug("Could not find default TaskExecutor bean", ex);         try {           return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);         }         catch (NoSuchBeanDefinitionException ex2) {           logger.info("No task executor bean found for async processing: " +               "no bean of type TaskExecutor and no bean named 'taskExecutor' either");         }         // Giving up -> either using local default executor or none at all...       } }     return null; }

最后,拦截方法中doSubmit提交任务到选取的异步执行器executor中进行执行:

/**
   * Delegate for actually executing the given task with the chosen executor.
   * @param task the task to execute
   * @param executor the chosen executor
   * @param returnType the declared return type (potentially a {@link Future} variant)
   * @return the execution result (potentially a corresponding {@link Future} handle)
   */
  protected Object doSubmit(Callable task, AsyncTaskExecutor executor, Class returnType) {


    if (completableFuturePresent) {
      Future result = CompletableFutureDelegate.processCompletableFuture(returnType, task, executor);
      if (result != null) {
        return result;
      }
    }


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

3.1.2 切点AnnotationMatchingPointcut的执行逻辑

在buildPointCut方法中完成了切点的构造,如下:

/**
   * Calculate a pointcut for the given async annotation types, if any.
   * @param asyncAnnotationTypes the async annotation types to introspect
   * @return the applicable Pointcut object, or {@code null} if none
   */
  protected Pointcut buildPointcut(Set> asyncAnnotationTypes) {


    ComposablePointcut result = null;
    for (Class asyncAnnotationType : asyncAnnotationTypes) {
      Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
      Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(asyncAnnotationType);
      if (result == null) {
        result = new ComposablePointcut(cpc);
      }
      else {
        result.union(cpc);
      }
      result = result.union(mpc);
    }


    return result;
  }

这里为所以异步注解(@Async和自定义注解)定义了一个组合切点,完成切点的匹配:

在class上标注异步注解,或者在方法上标注异步注解;

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

其中isEligible方法用来判定当前bean是否和当前异步注解切点匹配,如下:

/**
   * Check whether the given class is eligible for advising with this
   * post-processor's {@link Advisor}.
   * 

Implements caching of {@code canApply} results per bean target class.    * @param targetClass the class to check against    * @see AopUtils#canApply(Advisor, Class)    */   protected boolean isEligible(Class targetClass) { Boolean eligible = this.eligibleBeans.get(targetClass);     if (eligible != null) {       return eligible; }     eligible = AopUtils.canApply(this.advisor, targetClass);     this.eligibleBeans.put(targetClass, eligible);     return eligible; }

满足匹配条件时,调用代理工厂ProxyFactory,创建bean的动态代理,JDK动态代理或者CGLIB动态代理,具体代理执行的逻辑和我们在前面Spring源码:Aop源码分析中是完全一致的;

最后,异步注解的方法声明的类完成了动态代理过程,在执行增强逻辑,即拦截器方法的时候,将异步注解方法包装为一个task,放到异步执行器中进行调度执行;

————————————————

出处:https://blog.csdn.net/supzhili/article/details/99169875

你可能感兴趣的:(Spring boot @EnableAsync与@Async源码分析)