在项目开发过程中经常会用到多线程及线程池,通过异步的方式处理请求,从而提高系统的并发处理能力。SpringBoot通过自动装配的方式可以很简单的实现异步流程,通过@EnableAsync和@Async注解即可很轻松实现异步处理,那么具体Spring框架是如何实现异步的,下面将通过源码解读做深入了解。
注解@EnableAsync导入AsyncConfigurationSelector,AsyncConfigurationSelector根据注解@EnableAsync属性AdviceMode决定引入代理的创建方式ProxyAsyncConfiguration/AspectJAsyncConfiguration(最终@Async的切面操作都是通过代理来做的) 这里以ProxyAsyncConfiguration为例看看执行流程
其中通过AsyncAnnotationBeanPostProcessor为Spring Bean的后置处理器,主要作用是对于带有@Async注解的类或者类方法的bean做后置处理,将相关的bean包装为Proxy
AsyncAnnotationBeanPostProcessor拥有一个AsyncAnnotationAdvisor,这是一个Spring Advisor,会被包裹到方法或者bean级别使用了注解@Async或EJB 3.1 javax.ejb.Asynchronous注解的bean上 在容器启动时对每个bean 的初始化进行后置处理,则将自己所拥有的AsyncAnnotationAdvisor包裹到目标bean的最外面,其后置处理的逻辑是在其父类AbstractAdvisingBeanPostProcessor的postProcessAfterInitialization方法中实现的
Advisor由通知Advice和切入点Pointcut组成,AsyncAnnotationBeanPostProcessor所持AsyncAnnotationAdvisor对象最重要的是其包装在目标bean外面的AnnotationAsyncExecutionInterceptor。当使用者调用相应bean上的异步方法时,其实调用先到达代理对象,然后经过该AnnotationAsyncExecutionInterceptor,而该AnnotationAsyncExecutionInterceptor会使用异步机制调用目标bean对象上使用者指定要调用的方法 创建切入点和通知对象的方法如下
AnnotationAsyncExecutionInterceptor拦截器是MethodInterceptor的实现类,MethodInterceptor我们都很熟悉,就是通过代理的方式实现AOP的一种方式,而AnnotationAsyncExecutionInterceptor对MethodInterceptor的invoke方法的实现是在其父类AsyncExecutionInterceptor中
默认的如果BeanFactory中没有找到TaskExecutor类的bean,则使用SimpleAsyncTaskExecutor来异步执行任务。 SimpleAsyncTaskExecutor是一个伪线程池,这个线程池不重用线程,每次调用都会创建一个新的线程,所以在项目中如果要使用@Async来做异步任务,最好自定义一个TaskExecutor,如ThreadPoolTaskExecutor或ThreadPoolExecutor
@Override @Async(value = "customTaskExecutor") // value可省略,获取线程池的逻辑中会通过TaskExecutor类来获取bean public void initOpenDocumentResources() {}另外,如果要捕获异步任务执行过程中的异常,也需要自定义异常处理器AsyncUncaughtExceptionHandler
