文章
Spring @Async异步任务源码(1)—<task:annotation-driven/>、<task:executor/>、@EnableAsync解析
Spring @Async异步任务源码(2)—AsyncAnnotationBeanPostProcessor创建代理以及AnnotationAsyncExecutionInterceptor执行增强
Executor体系图
此处,重点关注ThreadPoolTaskExecutor,它使用jdk的ThreadPoolExecutor来实现spring的TaskExecutor接口,并且ThreadPoolTaskExecutor继承自ExecutorConfigurationSupport,它实现了BeanNameAware、InitializingBean、DisposableBean等接口(在图中并未表示出来)
异步任务执行案例
AsyncConfig
package com.zzhua.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
@Configuration
@EnableAsync
@ComponentScan
public class AsyncConfig {
private final LongAdder longAdder = new LongAdder();
/**
* 这里仅仅是配置了一个JDK的ThreadPoolExecutor
*/
@Bean
public Executor taskExecutor() {
return new ThreadPoolExecutor(3, 5, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), r -> {
longAdder.increment();
//线程命名
return new Thread(r, "JDK线程-" + longAdder.longValue());
});
}
/**
* 这里仅仅是配置了一个Spring的ThreadPoolTaskExecutor
*/
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(10);
//配置队列大小
executor.setQueueCapacity(800);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("threadPoolTaskExecutor1-");
// rejection-policy:拒绝策略,由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
/**
* 这里仅仅是配置了一个Spring的ThreadPoolTaskExecutor
*/
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(10);
//配置队列大小
executor.setQueueCapacity(800);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("threadPoolTaskExecutor2-");
// rejection-policy:拒绝策略,由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
AsyncMethod
@Component
public class AsyncMethod {
@Async
public void log() {
System.out.println("-----log:"+Thread.currentThread().getName());
}
@Async
public void log2() {
System.out.println("-----log2:"+Thread.currentThread().getName());
log3();
}
@Async
public void log3() {
System.out.println("-----log3:"+Thread.currentThread().getName());
}
}
AnnTaskExecutorTest
public class AnnTaskExecutorTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AsyncConfig.class);
AsyncMethod asyncMethod = ac.getBean(AsyncMethod.class);
System.out.println(asyncMethod.getClass());
System.out.println("--------" + Thread.currentThread().getName() + "--------");
asyncMethod.log();
asyncMethod.log2();
}
}
/*输出:
class com.zzhua.config.AsyncMethod$$EnhancerBySpringCGLIB$$7c242674
--------main--------
-----log:JDK线程-1
-----log2:JDK线程-2
-----log3:JDK线程-2
*/
其中log2调用log3方法,是用的目标对象调用,所以log3方法运行时,并不是以异步任务的方式执行的,仍然是在原来的[JDK线程-2]线程中执行的。
自己注入自己
尝试使用自己注入自己的方式(处理两个带@Transactional注解方法之间的调用时,可以使用这种方式解决事务不能传播的问题),解决这个问题,发现启动就报错了,看来不能用这种方式解决这个问题。
@Component
public class AsyncMethod {
/* 自己注入自己 */
@Autowired
private AsyncMethod asyncMethod;
@Async
public void log() {
System.out.println("-----log:"+Thread.currentThread().getName());
}
@Async
public void log2() {
System.out.println("-----log2:"+Thread.currentThread().getName());
/* 使用注入的对象调用log3 */
asyncMethod.log3();
}
//
@Async
public void log3() {
System.out.println("-----log3:"+Thread.currentThread().getName());
}
}
报错
class com.zzhua.config.AsyncMethod$$EnhancerBySpringCGLIB$$7c242674
--------main--------
-----log:JDK线程-1
-----log2:JDK线程-2
二月 20, 2023 4:33:19 下午 org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler handleUncaughtException
严重: Unexpected exception occurred invoking async method: public void com.zzhua.config.AsyncMethod.log2()
java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
at org.springframework.aop.framework.AopContext.currentProxy(AopContext.java:69)
at com.zzhua.config.AsyncMethod.log2(AsyncMethod.java:19)
at com.zzhua.config.AsyncMethod$$FastClassBySpringCGLIB$$fe247f8.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
报错原因分析(留个空)
普通bean的循环依赖
定义个A类,让它自己注入自己,Config作为配置类
@Component("a")
public class A {
@Autowired
private A a;
public A getA() {
return a;
}
}
@ComponentScan
public class Config {
}
public class TestAsync {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
Object a = ac.getBean("a");
System.out.println(a); // com.zzhua.config3.normal.A@548ad73b
}
}
看到上面执行是没有问题的,下面分析下过程:
首先,getBean(A),从getSingleton中获取,发现一级缓存中没有,并且当前的bean没有在正在创建当中,所以走doGetBean。然后,因为是单例,继续走getSingleton(与前面不是同一个方法),标记A正在创建当中,走创建A的逻辑,这个 时候判断,是否允许提前暴露,将提前获取A方法的lambda引用
形式放入三级缓存,然后走属性赋值,发现需要自动注入A,于是又一次getBean(A),(但是注意这一次去getBean(A)的时候,这个A是正在创建当中的,并且三级缓存中是已经存在了提前获取A方法的lambda引用
),仍然发现一级缓存中没有,但是A正在创建当中,此时尝试去二级缓存中拿,二级缓存也没有,并且此时是允许提前暴露的,于是从三级缓存中拿到了提前获取A方法的lambda引用
,调用此getEaryRefrence方法获取提前暴露的对象,并把结果放入二级缓存,移除三级缓存。此时已经拿到了A,这次的getBean(A)就已经算走完了,返回到将获取到的A注入给A对象的过程,然后A就完成了属性注入,然后走A的初始化过程,此时拿到之前是否允许提前暴露的标记,为true,走getSingleton方法,一级缓存中仍然没有,并且A正在创建当中,去二级缓存中找,找到了刚刚的A(这个A就是因为循环依赖而提前暴露出来的对象),然后比较A经过初始化后而暴露出来的对象(因为初始化过程有可能因为后置处理器的存在,而将这个A给换掉) 和 提前暴露出来的对象是否是同一个对象,如果是同一个对象,那spring认为没啥问题。但是,如果不是同一个对象,就会看看容器中除了因为类型检查而创建出来的bean是否已经注入了提前暴露出来的A对象,如果说这样的bean存在的话,那就有问题了,因为最终暴露出来的A对象和注入给其它bean的A对象不是同一个对象!而A对象又是个单例,这就尴尬了。spring这时就会报错。其中,还有一点要说明一下,为什么会存在bean已经注入提前暴露出来的A对象这种情况呢?因为A一旦发生了循环依赖,它就会提前暴露出来,如果循环依赖的关系比较复杂,比如下图:A被提前暴露出来以完成B的属性注入,可是B又需要注入C,C里面又要注入A,此时C里面去拿A的话,就是拿的提前暴露出来的A。
如果这个检查没有问题的话,返回到创建A的逻辑调用处(前面说到的第二个getSinleton方法),将创建好的A放入一级缓存,并从二级缓存和三级缓存中移除掉。后面,再去获取A的话,就直接走的一级缓存中拿。
理解了这个普通的情况,再来看下面的情况。
为什么代理bean的循环依赖没有问题,而async同样是基于代理的方式会存在问题呢?
我们需要注意的是,代理对象使用自动代理创建器,它的order比较高,而async使用的代理创建器,它的order比较低。
代理bean的循环依赖
代理的实现原理是依靠AbstractAutoProxyCreator,它实现了SmartInstantiationAwareBeanPostProcessor接口,这个接口中定义了getEarlyBeanReference方法,在这个方法里面,就会判断是否需要创建代理,如果发生循环依赖并且需要创建代理,则在提前暴露的时候,在getEarlyBeanReference方法中就创建代理了,而在后面的postProcessAfterInitialization方法中。
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 标记已经代理过的bean
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果当前的bean,没有提前暴露,那按需要就走代理
// 如果当前的bean,已经提前暴露,那就是已经走过代理了,没有必要再次走代理逻辑,直接返回传过来的bean
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// Initialize the bean instance.
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper);
// 经过后置处理暴露出来的对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
if (earlySingletonExposure) {
// 从二级缓存中,拿到提前暴露出来的对象(如果能拿到的话)
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果暴露出来的对象和最开始的bean是同一个的话,(这一点正好和AbstractAutoProxyCreator符合)
// 那就把提前暴露出来的对象作为最终返回
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 如果不是同一个的话,那就看有没有bean已经依赖了提前暴露出来的对象(除因为类型检查而被创建出来的bean)
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
}
}
async的bean循环依赖
而在async的AsyncAnnotationBeanPostProcessor中,它并没有实现SmartInstantiationAwareBeanPostProcessor接口,因此,如果这个bean要被async代理,那么AsyncAnnotationBeanPostProcessor将会在postProcessAfterInitialization方法中,把传入的bean给换成了代理对象,那么到后面的exposedObject == bean判断时,肯定就不相等了,而且自己依赖自己,就报错了。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || 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 proxy needed.
return bean;
}
async的bean和代理共存
使用@Lazy解决
@Component
public class AsyncMethod {
@Lazy
@Autowired
private AsyncMethod asyncMethod;
@Async
public void log() {
System.out.println("-----log:"+Thread.currentThread().getName());
}
@Async
public void log2() {
System.out.println("-----log2:"+Thread.currentThread().getName());
asyncMethod.log3();
}
@Async
public void log3() {
System.out.println("-----log3:"+Thread.currentThread().getName());
}
}
输出的结果
class com.zzhua.config3.AsyncMethod$$EnhancerBySpringCGLIB$$5a6a702a
--------main--------
-----log:JDK线程-1
-----log2:JDK线程-2
-----log3:JDK线程-3
有返回值的异步方法
AsyncConfig
@Configuration
@EnableAsync
@ComponentScan
public class AsyncConfig {
private final LongAdder longAdder = new LongAdder();
/**
* 这里仅仅是配置了一个JDK的ThreadPoolExecutor
*/
@Bean
public Executor taskExecutor() {
return new ThreadPoolExecutor(3, 5, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), r -> {
longAdder.increment();
//线程命名
return new Thread(r, "JDK线程-" + longAdder.longValue());
});
}
}
AsyncMethod
@Component
public class AsyncMethod {
/**
* 返回Future
*/
@Async
public Future<Integer> future(int i) throws InterruptedException {
System.out.println("-----执行future方法的线程:" + Thread.currentThread().getName());
Thread.sleep(2000);
ListenableFuture<Integer> integerListenableFuture = AsyncResult.forValue(i);
System.out.println("方法中的Future :" + integerListenableFuture);
return integerListenableFuture;
}
/**
* 返回CompletableFuture
*/
@Async
public CompletableFuture<Integer> completableFuture(int i) throws InterruptedException {
System.out.println("-----执行completableFuture方法的线程:" + Thread.currentThread().getName());
Thread.sleep(2000);
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.completedFuture(i);
System.out.println("方法中的CompletableFuture :" + integerCompletableFuture);
//int j=1/0;
return integerCompletableFuture;
}
/**
* 返回ListenableFuture
*/
@Async
public ListenableFuture<Integer> listenableFuture(int i) throws InterruptedException {
System.out.println("-----执行listenableFuture方法的线程:" + Thread.currentThread().getName());
Thread.sleep(2000);
ListenableFuture<Integer> integerListenableFuture = AsyncResult.forValue(i);
System.out.println("方法中的ListenableFuture :" + integerListenableFuture);
return integerListenableFuture;
}
/**
* 无返回
*/
@Async
public void noReturn(int i) throws InterruptedException {
System.out.println("-----noReturn:" + Thread.currentThread().getName());
Thread.sleep(3000);
//制造一个异常
int j = 1 / 0;
}
}
MyAsyncConfigurer
@Component
public class MyAsyncConfigurer implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
/**
* 自定义异常处理逻辑
* @param ex 抛出的异常
* @param method 抛出异常的方法
* @param params 抛出异常的方法参数
*/
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
System.out.println("-----自定义异常处理-------");
System.out.println(method.getName());
System.out.println(ex.getMessage());
System.out.println(Arrays.toString(params));
System.out.println("-----自定义异常处理-------");
}
};
}
}
TestAsync
public class TestAsync {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AsyncConfig.class);
AsyncMethod asyncMethod = ac.getBean(AsyncMethod.class);
System.out.println(asyncMethod.getClass());
System.out.println("--------" + Thread.currentThread().getName() + "--------");
/*
* 1 future
*/
Future<Integer> future = asyncMethod.future(0);
System.out.println("FutureTask中获取结果并进行操作的线程: " + Thread.currentThread().getName());
//get()方法只能同步获取执行结果并进行其他操作,因此可能还是会阻塞调用线程,或者需要手动新开线程等待结果,功能比较简陋
System.out.println(future.get() + 10); // 主线程将在此阻塞
System.out.println("返回的Future :" + future); // AsyncResult@200f8c0d
/*
* 2 completableFuture
*/
CompletableFuture<Integer> integerCompletableFuture = asyncMethod.completableFuture(1);
//注册一个正常回调函数,当执行完毕时自动回调该函数,参数就是执行结果,这样就不必同步等待了
integerCompletableFuture.thenApplyAsync(integer -> {
System.out.println("CompletableFuture中获取结果并进行操作的线程:: " + Thread.currentThread().getName());
System.out.println(integer + 10);
return null;
});
//注册一个异常回调函数,当执行抛出异常时时自动回调该函数
integerCompletableFuture.exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
// CompletableFuture@55b699ef[Not completed, 2 dependents]
System.out.println("返回的CompletableFuture :" + integerCompletableFuture);
/*
* 3 listenableFuture
*/
ListenableFuture<Integer> integerListenableFuture = asyncMethod.listenableFuture(2);
//注册一个回调函数,具有异常方法和正常方法,当正常执行完毕时自动回调onSuccess,参数就是执行结果,这样就不必同步等待了
integerListenableFuture.addCallback(new ListenableFutureCallback<Integer>() {
//执行异常自动回调,onFailure中抛出的异常被忽略
@Override
public void onFailure(Throwable o) {
o.printStackTrace();
}
//执行成功自动回调,onSuccess中抛出的异常被忽略
@Override
public void onSuccess(Integer o) {
System.out.println("ListenableFuture中获取结果并进行操作的线程: " + Thread.currentThread().getName());
System.out.println(o + 10);
}
});
// ListenableFutureTask@61862a7f
System.out.println("返回的ListenableFuture :" + integerListenableFuture);
/*
* 3 noReturn
*/
asyncMethod.noReturn(1);
}
}
配置原理
xml配置
- <task:annotation-driven/>
- AsyncAnnotationBeanPostProcessor、
- ScheduledAnnotationBeanPostProcessor
- <task:executor/>
- TaskExecutorFactoryBean(getObject => 返回TaskExecutor类型)
注解配置
@EnableAsync
假设使用@EnableAsync注解所在的配置类为AsyncConfig,而@EnableAsync注解实质上使用了@Import作为元注解,并且导入的是ImportSelector类型,那么ImportSelector#selectImport方法返回的类数组,其中每个类都会被视为配置类,并且能够拿到AsyncConfig上的@EnableAsync注解实例的数据。
ProxyAsyncConfiguration
ProxyAsyncConfiguration里面定义了bean:AsyncAnnotationBeanPostProcessor。ProxyAsyncConfiguration的父类AbstractAsyncConfiguration,会自动注入容器中的AsyncConfigurer异步配置器(只允许一个),从这个异步配置器中获取executor和AsyncUncaughtExceptionHandler。然后子类ProxyAsyncConfiguration把这2个组件设置给bean:AsyncAnnotationBeanPostProcessor
AsyncAnnotationBeanPostProcessor
在BeanFactoryAware接口的实现中会创建AsyncAnnotationAdvisor这个切面(也叫通知器)
代理中的Advised
之前没有注意到这个东西,ProxyConfig里有个配置isOpaque,表示是否让代理对象实现Advised接口,如果实现了这个接口,那就代表这个代理对象可以使用Advised接口中定义的方法了,比如添加Advisor。那么它是如何实现的呢?就要注意到CglibAopProxy的构造方法里面,把传进来的advised给了AdvisedDispatcher,而AdvisedDispatcher是cglib中的callback回调类型的一种,当父类方法传给ProxyCallbackFilter的accept方法时,发现方法是Advised接口中的方法并且opaque的配置为false,则会返回在callbacks数组中的索引4,即AdvisedDispatcher类型。如果返回的是这个类型,代理类会类似
如下重写这个方法:
public final void dispatcher() {
// 获取绑定的回调对象
Dispatcher var10000 = this.CGLIB$CALLBACK_5;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_5;
}
// 调用回调对象的loadObject方法,将返回的结果去调用dispatcher方法
((MyService)var10000.loadObject()).dispatcher();
}
我们看到它是直接调用Dispatcher#loadObject方法,而在AdvisedDispatcher中的loadObject方法是这样的:
private static class AdvisedDispatcher implements Dispatcher, Serializable {
private final AdvisedSupport advised;
public AdvisedDispatcher(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object loadObject() {
return this.advised;
}
}
它里面是直接返回构造方法中传入的Advised,然后调用advised的addAdvisor方法,也就达到了修改advised中的advisor的目的,后面当调用其它方法时,会获取advised的切面(刚刚通过addAdvisor方法加的切面也包含在内),也就扩展了增强链。那么其实,我们拿到代理对象,也可以把它强转为Advised接口(前提是opaque设置为false),然后即使在代码运行的过程中,我们也可以动态的添加增强链了
AsyncAnnotationAdvisor
切面(即:通知器)由 切点 + 增强 所组成。这里切点用的是AnnotationMatchingPointcut,增强用的是AnnotationAsyncExecutionInterceptor
AnnotationMatchingPointcut
用来匹配类上或方法上指定的注解。
检查类上的注解
使用的是Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
其中classFilter的实现是:AnnotationClassFilter,它AnnotatedElementUtils.hasAnnotation(clazz, this.annotationType)获取类,以及父类上的注解。或者clazz.isAnnotationPresent(this.annotationType))检查指定类上的注解(不包括父类)。
检查方法上的注解
使用的是Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);
其中methodMatcher的实现是:AnnotationClassFilter,它AnnotatedElementUtils.hasAnnotation(method, this.annotationType)获取方法,以及父类方法上的注解。或者clazz.isAnnotationPresent(this.annotationType))检查指定方法上的注解(不包括父类)。
AnnotationAsyncExecutionInterceptor
其中核心方法位于父类中AsyncExecutionInterceptor,它里面首先需要确定AsyncTaskExecutor异步执行器,框架里,它默认使用默认SimpleAsyncTaskExecutor,这个执行器别用!!!
/**
1. AsyncExecutionInterceptor的方法
2. <p>
3. 截获给定的方法调用,将方法的实际调用提交到正确的任务执行器,并立即返回给调用方。
4. 5. @param invocation 拦截的进行异步调用的方法
6. @return 如果原始方法返回"Future",则返回Future,否则返回null
*/
@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);
//如果为null,直接抛出异常
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
//创建线程任务
Callable<Object> task = () -> {
try {
//任务内部就是invocation.proceed(),也就是向后执行其他拦截器或者目标方法的逻辑
Object result = invocation.proceed();
//如果返回结果属于Future,那么等待获取结果
//如果不是Future,那么直接返回null,也就是说对于异步任务方法的返回值如果不是Feature类型,那么将始终获取null
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());
}
//返回null
return null;
};
//使用所选执行器实际执行给定任务的委托
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
典型的单例模式-SingletonSupplier
在AsyncExecutionAspectSupport中使用了使用到了该类
public class SingletonSupplier<T> implements Supplier<T> {
@Nullable
private final Supplier<? extends T> instanceSupplier;
@Nullable
private final Supplier<? extends T> defaultSupplier;
@Nullable
private volatile T singletonInstance;
// ...
@Override
@Nullable
public T get() {
T instance = this.singletonInstance;
if (instance == null) {
synchronized (this) {
instance = this.singletonInstance;
if (instance == null) {
if (this.instanceSupplier != null) {
instance = this.instanceSupplier.get();
}
if (instance == null && this.defaultSupplier != null) {
instance = this.defaultSupplier.get();
}
this.singletonInstance = instance;
}
}
}
return instance;
}
public T obtain() {
T instance = get();
Assert.state(instance != null, "No instance from Supplier");
return instance;
}
// ...
}
doSubmit
/**
* AsyncExecutionAspectSupport的方法
* <p>
* 使用所选执行器实际执行给定的任务委托。
* <p>
* 异步方法支持三种返回值类型(排除void),其他类型的返回值将最终返回null
*
* @param task 要执行的任务
* @param executor 所选执行器
* @param returnType 声明的返回类型(可能是Feature的各种子类)
* @return 执行结果(可能是相应的Future对象)
*/
@Nullable
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
/*
* 首先判断如果返回值类型是CompletableFuture及其子类,那么最终会默认返回一个Spring为我们创建的CompletableFuture对象;
*/
if (CompletableFuture.class.isAssignableFrom(returnType)) {
//使用给定的执行器,异步执行任务
return CompletableFuture.supplyAsync(() -> {
try {
return task.call();
} catch (Throwable ex) {
throw new CompletionException(ex);
}
}, executor);
}
/*
* 其次判断如果返回值类型是ListenableFuture及其子类,那么最终会默认返回一个Spring为我们创建的ListenableFutureTask对象。
*/
else if (ListenableFuture.class.isAssignableFrom(returnType)) {
//通过给定的执行器,异步执行任务
return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
}
/*
* 随后判断如果异步方法返回值类型是Future及其子类,那么最终会默认返回一个Spring为我们创建的FutureTask对象;
*/
else if (Future.class.isAssignableFrom(returnType)) {
//通过给定的执行器,异步执行任务
return executor.submit(task);
}
/*最后,如果以上判断都不满足,即如果异步方法指定了返回其它类型,那么最终将返回一个null。最终返回的结果对象,和我们在方法中返回的对象不是同一个。*/
else {
//通过给定的执行器,异步执行任务
executor.submit(task);
return null;
}
}
handleError
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
if (Future.class.isAssignableFrom(method.getReturnType())) {
ReflectionUtils.rethrowException(ex); // 同 throw xxx
} else {
//获取异常处理器并且执行调用
try {
this.exceptionHandler.obtain().handleUncaughtException(ex, method, params);
} catch (Throwable ex2) {
//如果异常处理器抛出异常,那么该异常仍然不会被抛出,仅仅是记录日志!
logger.warn("Exception handler for async method '" + method.toGenericString() + "threw unexpected exception itself", ex2);
}
}
}