Spring 源码学习 - @Async注解实现原理

1,481 阅读3分钟

本文作者:geek,一个聪明好学的朋友

Spring 源码学习 - @Async注解实现原理

1. 简介

开发中我们需要异步执行某个耗时任务时候需要@Async,以下我将从源码角度解释该注解的实现原理。

2.前提条件@EnableAsync

​ 项目使用中,需要添加@EnableAsync注解支持,才能使用@Async(也支持自定义注解)生效。@EnableAsync(默认mode为AdviceMode.PROXY情况下)作用为了给spring项目加入AsyncConfigurationSelector,从而引入AsyncAnnotationBeanPostProcessor。

@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {}
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");
  /**
   *  创建postProcessor,支持定制executor与exceptionHandler
   */
    AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
  bpp.configure(this.executor, this.exceptionHandler);
  Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
  if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
   bpp.setAsyncAnnotationType(customAsyncAnnotation);
  }
  bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
  bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
  return bpp;
 }

}

3.AsyncAnnotationBeanPostProcessor的作用

AsyncAnnotationBeanPostProcessor为加了@Async注解的方法的目标类加入AsyncAnnotationAdvisor。AsyncAnnotationAdvisor也即是spring AOP中责任链调用的advisor,可见被@Async的实现是通过生成代理对象来实现的。
public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {

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

}
public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
public AsyncAnnotationAdvisor(
   @Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

  /**
  *  支持Async与Asynchronous
  */
  Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(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.
  }
  this.advice = buildAdvice(executor, exceptionHandler);
  this.pointcut = buildPointcut(asyncAnnotationTypes);
 }
  
  /**
  * // 这个最终又是委托给`AnnotationAsyncExecutionInterceptor`,它是一个具体的增强器,有着核心内容
  * @param executor
  * @param exceptionHandler
  * @return
  */
 protected Advice buildAdvice(
   @Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

  AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
  interceptor.configure(executor, exceptionHandler);
  return interceptor;
 }
 }

4.AnnotationAsyncExecutionInterceptor核心内容

​ AnnotationAsyncExecutionInterceptor继承AsyncExecutionInterceptor间接实现了MethodInterceptor,该拦截器的实现的invoke方法把原来方法的调用提交到新的线程池执行,从而实现了方法的异步。当需要获得异步结果时,支持CompletableFuture,ListenableFuture,Future的返回。

public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {@Override
 @Nullable
 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");
  }
    /**
    *  构建放到AsyncTaskExecutor执行Callable Task
    */
  Callable<Object> task = () -> {
   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());
 }
}

5. 使用注意事项

5.1使用@Aysnc的时候最好配置一个线程池Executor以让线程复用节省资源,或者为SimpleAsyncTaskExecutor设置基于线程池实现的ThreadFactory,在否则会默认使用SimpleAsyncTaskExecutor,该executor会在每次调用时新建一个线程。

/**
* SimpleAsyncTaskExecutor继承自CustomizableThreadCreator,可以看到线程直接new
*/
public class CustomizableThreadCreator implements Serializable { 
public Thread createThread(Runnable runnable) {
  Thread thread = new Thread(getThreadGroup(), runnable, nextThreadName());
  thread.setPriority(getThreadPriority());
  thread.setDaemon(isDaemon());
  return thread;
 }
}

5.2关于方法内部调用,@Async注解会失效

public class QueryServiceImpl implements QueryService {
 @Override
 public void A() {
  System.out.println("QueryServiceImpl.A");
  B();
 }

 @Async
 @Override
 public void B() {
  System.out.println("QueryServiceImpl.B");
 }
}

​ 失效原因:A方法中调用B方法,调用即为this.B(),this对象为原始的对象,并不是增强后代理对象,当然不能生效了。建议重构分开调用,如果硬是需要内部调用则是只能通过获取代理对象来实现。

@Component("q")
public class QueryServiceImpl implements QueryService {

 @Autowired
 private ApplicationContext applicationContext;


 @Override
 public void A() {
  System.out.println("QueryServiceImpl.A");
  QueryService queryService = (QueryService)applicationContext.getBean("q");
  queryService.B();
 }

 @Async
 @Override
 public void B() {
  System.out.println("QueryServiceImpl.B");
 }
}

参考

查看更多文章关注公众号:好奇心森林 Wechat