不僅會用@Async,我把源碼也梳理了一遍(下)
原創: 呂一明 java思維導圖 昨天
終於到了源碼分析的環節了,在這之前我已經寫過了兩篇文章專門分析這個@Async了,還沒看過的同學先去看下哈。
好了,不囉嗦。
分析過程:
-
開啓異步代理
-
初始化excutor和exceptionHandler
-
定義切面處理
-
線程處理
開啓異步化支持
@EnableAsync
@EnableAsync是開啓某個模塊的功能加載,之前在《導圖梳理springboot手動、自動裝配,讓springboot不再難懂》介紹過,@EnableXXX一般都有兩種用法,一種直接引入配置,一種可以通過註解的元數據選擇需要導入的配置。這裏的@EnableAsync明顯屬於第二種。
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AsyncConfigurationSelector.class) public @interface EnableAsync { // 默認是@Async和EJB3.1規範下的@Asynchronous註解, // 這裏表示可以自定義註解啓動異步 Class<? extends Annotation> annotation() default Annotation.class; // true表示啓用CGLIB代理 boolean proxyTargetClass() default false; // 切面通知模式:默認動態代理PROXY AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; }
這個EnableAsync註解,一般註解屬性我們都不需要改,默認就行了。那麼這裏最重要的代碼就只有一行了,就是這個@Import(AsyncConfigurationSelector.class),導入AsyncConfigurationSelector配置。
AsyncConfigurationSelector
我們打開AsyncConfigurationSelector看看:
-
/* * 關鍵點: * 1、父類AdviceModeImportSelector * 2、導入配置類ProxyAsyncConfiguration * */ public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> { private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME = "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"; @Override @Nullable public String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {ProxyAsyncConfiguration.class.getName()}; case ASPECTJ: return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } } }
上面的源碼裏面,我在開頭寫了2個關鍵點,
-
一個是父類AdviceModeImportSelector
-
二是導入配置類ProxyAsyncConfiguration
大家在源碼分析的時候這樣去看源碼,當你打開一個類的時候,裏面有很多個方法,你不知道你應該從哪個方法看起,你第一時間可以先去看繼承關係,就比如這AsyncConfigurationSelector類,他繼承了AdviceModeImportSelector,但AdviceModeImportSelector其實又實現了ImportSelector,而ImportSelector是我們比較熟悉的接口。我們知道ImportSelector裏面有個方法selectImports(AnnotationMetadata)是用於根據註解屬性導入配置的,所以這裏就是我們的突破口。
所以綜合來看源碼的方法是這樣的:
當你打開一個類,比較迷茫的時候:
-
第一步:打開類的繼承關係圖(Ctrl+Shift+Alt+u)
找你熟悉的一些接口,如果是Spring,特別需要注意spring的Aware系列接口,比如:
-
BeanNameAware :可以獲取容器中bean的名稱
-
BeanFactoryAware:獲取當前bean factory這也可以調用容器的服務
-
ApplicationContextAware:當前的applicationContext, 這也可以調用容器的服務
-
MessageSourceAware:獲得message source,這也可以獲得文本信息
-
applicationEventPulisherAware:應用事件發佈器,可以發佈事件,
-
ResourceLoaderAware:獲得資源加載器,可以獲得外部資源文件的內容;
這些都有一些特殊的功能,在spring項目被啓動的時候會被調用對應的實現接口,所以看到這些Aware實現類的時候,如果你比較迷茫,可以從Aware的實現類的接口重寫開始看。
而剛纔我們說到的ImportSelector也是spring的一個比較特殊的接口了,我們就從selectImports(AnnotationMetadata)方法看起:
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
protected String getAdviceModeAttributeName() {
return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME;
}
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(),
AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
// 獲取@EnableAsync的屬性值
AnnotationAttributes attributes =
AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
// 調用抽象方法,由子類重寫
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
/**
* 由子類AsyncConfigurationSelector重寫了這個方法
*/
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
}
所以從這個方法看起你就很容易梳理到代碼了。上面代碼中,首先把EnableAsync的元數據都封裝到AnnotationAttributes中,然後再獲取到AdviceMode,最後選擇出需要導入的配置,而導入的配置方法是個抽象方法selectImports(AdviceMode),由子類重寫。子類自然就是AsyncConfigurationSelector,所以你纔可以看到AsyncConfigurationSelector裏有個selectImports方法,其實是重寫了父類的。
現在邏輯相對清晰了,由於AdviceMode默認就是AdviceMode.PROXY,所以我們導入的配置就是ProxyAsyncConfiguration,接下來我們再去分析。
ProxyAsyncConfiguration
這看配置類的名稱,翻譯過來就是代理異步配置。有時候我們看源碼也要從一個類的名稱去猜測可能的功能。我們之前在第二篇文章中猜想過,應該有個Aop切面處理@Async註解,如果大家熟悉aop的原理的話,aop也是使用的了代理。那麼應該就是在這個配置類裏面實現的了。
好了,由一個名字我想了這麼多,接下來先看下代碼:
/*
* 這裏的關鍵點有2個:
* 1、父類AbstractAsyncConfiguration
* 2、初始化對象AsyncAnnotationBeanPostProcessor
*
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
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");
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;
}
}
上面我依然點出了兩個重點:
-
1、父類AbstractAsyncConfiguration
2、初始化對象AsyncAnnotationBeanPostProcessor
爲什麼一直強調父類,因爲子類初始化之前,父類是要先完成初始化的,所以加載順序都是父類先加載,這點必須清楚,另外就是子類一般都要重寫父類的方法,重寫的方法一般在父類的其他方法中會被調用。
既然是繼承關係,我們依然來看下繼承關係圖: 上面我們就看到了上面我說過的Aware系列的接口之一ImportAware,作用是通過實現ImportAware接口獲取對應註解的元數據。
所以,我們先去看完父類AbstractAsyncConfiguration,然後再回頭來看子類ProxyAsyncConfiguration。
@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableAsync;
@Nullable
protected Supplier<Executor> executor;
@Nullable
protected Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;
/**
* 通過實現ImportAware接口獲取@EnableAsync的屬性值
* @param importMetadata
*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
if (this.enableAsync == null) {
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
/**
* Collect any {@link AsyncConfigurer} beans through autowiring.
*
* 導入自定義的實現了AsyncConfigurer接口的bean
* 並給executor、exceptionHandler附上自定義的值
*
*/
@Autowired(required = false)
void setConfigurers(Collection<AsyncConfigurer> configurers) {
// 如果沒有自定義實現AsyncConfigurer接口,直接返回
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException("Only one AsyncConfigurer may exist");
}
// 有的話,直接賦值
AsyncConfigurer configurer = configurers.iterator().next();
this.executor = configurer::getAsyncExecutor;
this.exceptionHandler = configurer::getAsyncUncaughtExceptionHandler;
}
}
1、setImportMetadata方法裏讀取了EnableAsync的元數據存在了AnnotationAttributes 中。2、setConfigurers導入自定義的AsyncConfigurer配置類。
我們在第一篇文中就自定義了線程池,還有異步線程的錯誤處理器等,就是通過實現AsyncConfigurer接口實現的,而我們自定義的類就會被注入到setConfigurers這個方法中,然後被賦值給當前類的executor和exceptionHandler。
所以這個父類中,其實就是一些初始化,初始化this.enableAsync、this.executor和this.exceptionHandler。
當然了,我們不是必須要實現AsyncConfigurer重寫executor和exceptionHandler,所以this.executor和this.exceptionHandler可能還是爲null的。
我們再回到ProxyAsyncConfiguration的asyncAdvisor()方法,看這個方法名稱,有點異步切面的意思呀,那麼返回值AsyncAnnotationBeanPostProcessor是否就是一個切面增強類呢?這個我們去看下繼承關係。 繼承的東西比較多,先來說說我們比較熟悉的東西:
-
BeanClassLoaderAware - 獲取當前類的類加載器
-
BeanFactoryAware - 獲取Spring的核心容器BeanFactory
-
BeanPostProcessor - bean初始化過程中的前置、後置處理器
-
AbstractAdvisingBeanPostProcessor - 生成aop代理的後置處理器
那麼現在來梳理一下邏輯,首先ProxyAsyncConfiguration中會開始初始化AsyncAnnotationBeanPostProcessor,因爲是@Bean,所以在對象注入spring容器之前,你先不用看aware系列,不用看BeanPostProcessor,先看@Bean裏面方法的內容,那是注入spring容器之前可能做一些初始化。
而asyncAdvisor()方法中,關鍵的代碼其實也沒多少,邏輯如下:1、就是new一個AsyncAnnotationBeanPostProcessor對象 2、bpp.configure(this.executor, this.exceptionHandler);就是賦值excutor和exceptionHandler:
-
AsyncAnnotationBeanPostProcessor#configure
public void configure(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
this.executor = executor;
this.exceptionHandler = exceptionHandler;
}
3、bpp.setAsyncAnnotationType(customAsyncAnnotation);
如果有自定義的異步註解就賦值然後就返回了對象,通過@Bean註解,這時候這個new出來的AsyncAnnotationBeanPostProcessor對象就會注入到spring容器中,進而調用aware和beanPostProcessor那一套流程。
AsyncAnnotationBeanPostProcessor
接下來就是重點之中的重點了,可以說@Async的重點核心就是這個類,之前做了這麼多準備就是爲了初始化這個類。
我們來回顧一下上面的內容,首先我們獲得了自定義的excutor和exceptionHandler,然後新建了AsyncAnnotationBeanPostProcessor對象並注入到了spring容器中,因爲bean的生命週期比較複雜。
我怕很多人沒研究過spring的容器,對spring bean的聲明週期不太瞭解,特意從網上找了一張總結的圖,讓大家一張圖搞懂Spring bean的生命週期,從Spring容器啓動到容器銷燬bean的全過程。 通過這個圖,我們再回到我們的這個AsyncAnnotationBeanPostProcessor這個類的繼承關係圖,你就知道了執行的順序流程如下:
-
1、因爲實現了BeanPostProcessor,所以先執行postProcessBeforeInitialization
-
2、執行構造器方法
-
3、執行BeanFactoryAware 、BeanClassLoaderAware的對應方法
-
4、執行BeanPostProcessor的postProcessAfterInitialization方法
ok,順序已給出,那麼初始化的過程就清晰了,接下來我們只需要一步一步去看對應模塊的代碼。
-
第一步:postProcessBeforeInitialization
好像啥都沒做,忽略
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
-
第二步:構造器
其實對象我們是new出來的,然後再通過@Bean注入容器的,並不是使用@Component或者xml方式注入,所以構造器應該是早就執行了
public AsyncAnnotationBeanPostProcessor() {
setBeforeExistingAdvisors(true);
}
這個構造器只有一行代碼,是說是不是在其他已存在的aop之前執行,參數表示是的。
-
第三步:BeanClassLoaderAware、BeanFactoryAware
因爲BeanClassLoaderAware是aop代碼部分的了,是爲了給對象生成代理的時候統一類加載器。所以這個方法我們不需要看。
我們來看下BeanFactoryAware的setBeanFactory方法:
-
AsyncAnnotationBeanPostProcessor#setBeanFactory
@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;
}
代碼中,除了引入beanFactory之外,還定義了一個切面advisor ,並把切面advisor賦值給當前對象。
我們中篇文中說過,用編碼實現一個aop,需要準備幾個東西:
-
ProxyFactory 代理工廠
-
Pointcut 切點
-
Advice 通知
-
Advisor 切面
-
Target 被代理對象
有了這幾個組件之後,我們就可以構建成一個aop。
那麼再看這裏代碼,這裏的advisor就在這裏初始化獲取到了。而我們可以這樣理解:Advisor = pointcut + Advice ,所以可說,我們完成了切面的初始化,其實也是@Async核心重要的一部分了。
ok,有了知識儲備,搞啥都清晰。我們接着往下面走, 看AsyncAnnotationAdvisor的初始化過程先,也就是構造方法:
public AsyncAnnotationAdvisor(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
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);
}
上面重點是這兩行:
this.advice = buildAdvice(executor, exceptionHandler);
this.pointcut = buildPointcut(asyncAnnotationTypes);
切面等於切點加通知處理。就是這兩樣東西了。也就是構造器裏面其實得到了切點和通知。接下來我們繼續看着兩個方法:
-
AsyncAnnotationAdvisor#buildAdvice
protected Advice buildAdvice(
@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
AnnotationAsyncExecutionInterceptor interceptor = new
AnnotationAsyncExecutionInterceptor(null);
interceptor.configure(executor, exceptionHandler);
return interceptor;
}
我們先來看下AnnotationAsyncExecutionInterceptor的繼承關係:
這裏面我們比較熟悉的類有Advice、Interceptor、BeanFactoryAware。結合第二篇文章中講到的生成aop的編碼實現。你基本可以確定,這個AnnotationAsyncExecutionInterceptor類就是我們環繞通知的處理類了,Advice說明了這個類是個aop通知處理類,Interceptor說明了處理的方法是攔截器的invoke方法。切面攔截到切點時候就會到這個方法的invoke中執行對應的業務處理邏輯。
那麼對應到@Async,執行的邏輯應該就是起一個線程執行方法。
清楚了這一點之後,我們再回到AnnotationAsyncExecutionInterceptor構造方法中,最終調用的是父類中的構造方法:
public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor) {
this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () ->
getDefaultExecutor(this.beanFactory));
this.exceptionHandler = SingletonSupplier.of(SimpleAsyncUncaughtExceptionHandler::new);
}
這裏就是給executor和exceptionHandler一個初始化的執行器或錯誤處理器,初始化默認處理器之後再執行interceptor.configure(executor, exceptionHandler);
public void configure(@Nullable Supplier<Executor> defaultExecutor,
@Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () ->
getDefaultExecutor(this.beanFactory));
this.exceptionHandler = new SingletonSupplier<>(exceptionHandler,
SimpleAsyncUncaughtExceptionHandler::new);
}
這意思就是如果我們之前自定義了執行器和錯誤處理器,那麼用我們自定義的,如果沒有就用剛剛在構造器中初始化的默認的。
所以,切面的環繞通知處理Advice已經生成。我們再來看看另一個方法
-
AsyncAnnotationAdvisor#buildPointcut
protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
ComposablePointcut result = null;
for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);
if (result == null) {
result = new ComposablePointcut(cpc);
}
else {
result.union(cpc);
}
result = result.union(mpc);
}
return (result != null ? result : Pointcut.TRUE);
}
這生成切點的邏輯也挺簡單的,之前允許在@EnableAsync中通過annatation定義自定義的異步線程註解,我們常用的默認是@Async。所以這裏意思其實是把所有的可能的註解都union起來,union就是合併意思。不管自定義的,還是默認的都作爲切點。
這時候切點Pointcut已初始化好。
所以在AsyncAnnotationAdvisor中我們初始化好了Advice和Pointcut,而切面就等於Advice+Pointcut,那麼它是一個切面來的嗎?我們來看下繼承關係: 果然實現了Advisor,是個切面。所以致此,我們已經定義了一個切面。
-
第四步:執行BeanPostProcessor的postProcessAfterInitialization方法
上面三步走完之後,我們定義得到了一個切面,接下來我們進入最後一步,就是bean的後置處理,這個後置處理器其實是aop中實現的,所以我們定義一個aop切面,其實都需要進入這個後置處理器,那麼這裏面做了什麼事情呢?
@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;
}
看了裏面的邏輯,應該就是直接給bean生成代理的了,那麼我們寫的Async代碼中,那些需要我們生成代理呢,是不是所有寫了@Async註解的方法或者類?因爲我知道aop通過ProxyFactory生成代理的,所以我在 ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName); 這裏打個端點,然後啓動項目。 果然,需要代理的是UserServiceImpl,因爲我的@Async方法都是寫在UserServiceImpl上的: 所以UserServiceImpl就是aop需要代理的對象。其中prepareProxyFactory的代碼如下:
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
return proxyFactory;
}
就是創建proxyFactory對象,然後設置目標代理對象就是UserServiceImpl,然後接着走是設置interface的,
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
其中evaluateProxyInterfaces的內容是:
可以看到因爲UserServiceImpl是個實現類,所以對應的接口需要聲明,這樣使用UserService調用方法時候纔會觸發aop。所以這裏面的重要代碼就是proxyFactory.addInterface(ifc);
然後方法繼續執行,就到了proxyFactory.addAdvisor(this.advisor);這一句,advisor就是我們上面初始化好的切面,這裏直接set給proxyFactory,定義切點,和切面處理。
再接着走,到了customizeProxyFactory(proxyFactory);這一步其實可以重寫,然後proxyFactory自定義一些需要的屬性等。@Async中沒有重寫,所以這一步我們跳過。
最後到了代碼*return *proxyFactory.getProxy(getProxyClassLoader());這一步,是不是aop生成代理了。
源碼梳理
所以總結我們上面所有的內容,我們再來梳理一下proxyFactory的僞代碼過程:
ProxyFactory proxyFactory = new ProxyFactory();
// 目標代理類
proxyFactory.setTarget("UserServiceImpl bean");
// 代理接口
proxyFactory.addInterface("UserService");
// 切點
AsyncAnnotationAdvisor.pointcut = @Async註解
// 環繞通知處理
AsyncAnnotationAdvisor.advice = AnnotationAsyncExecutionInterceptor攔截器
// 切面 = 切點+通知
proxyFactory.addAdvisor("AsyncAnnotationAdvisor");
// 生成代理
UserService userService = proxyFactory.getProxy(getProxyClassLoader());
結合我們第二篇文章中的aop編碼實現方式,是不是很相似了。所以這時候aop我們已經完全定義好了。
接下來我們回頭來看環繞通知處理裏面的業務邏輯,因爲現在aop已經生成,攔截@Async之後我們需要異步處理代理的方法。這時候我們進入AnnotationAsyncExecutionInterceptor的invoke方法。
-
在父類中AsyncExecutionInterceptor#invoke
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);
// 獲取executor執行器
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
// 定義一個Callable異步線程
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());
}
上面第一步獲取到executor,然後再通過Callable定義一個異步線程。然後把task放在doSubmit中執行。
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
if (CompletableFuture.class.isAssignableFrom(returnType)) {
return CompletableFuture.supplyAsync(() -> {
try {
return task.call();
}
catch (Throwable ex) {
throw new CompletionException(ex);
}
}, executor);
}
else if (ListenableFuture.class.isAssignableFrom(returnType)) {
return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
}
else if (Future.class.isAssignableFrom(returnType)) {
return executor.submit(task);
}
else {
executor.submit(task);
return null;
}
}
這裏面就明顯了,就是去執行我們的task,然後返回結果。具體的我們就不再去深究啦。相信到了這一步,我們已經明白了@Async的原理。
以上就是@Async的源碼分析,相對來說還是比較簡單,看過aop源碼的人再來看@Async的話幾乎都不用花什麼時間,所以技術這東西我們要學會多積累。
總結
好啦,今天的文章先到這裏了。
如果你喜歡我的文章,歡迎關注我的公衆號:java思維導圖,給我點個在看或者轉發一下,萬分感謝哈!