@Async学习及循环依赖

文章

@Async Spring异步任务的深入学习与使用

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);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值