写点什么

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

发布于: 2020 年 06 月 21 日
Spring 源码学习 -  @Async注解实现原理

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

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"); }}
复制代码

参考


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


发布于: 2020 年 06 月 21 日阅读数: 116
用户头像

还未添加个人签名 2017.10.17 加入

11年入行互联网,关注技术和金融。

评论

发布
暂无评论
Spring 源码学习 -  @Async注解实现原理