不僅會用@Async,我把源碼也梳理了一遍(下)

  • 2019 年 10 月 8 日
  • 筆記

終於到了源碼分析的環節了,在這之前我已經寫過了兩篇文章專門分析這個@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的話幾乎都不用花什麼時間,所以技術這東西我們要學會多積累。