@Async源碼實現

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

原創: 呂一明 java思維導圖 昨天

 

終於到了源碼分析的環節了,在這之前我已經寫過了兩篇文章專門分析這個@Async了,還沒看過的同學先去看下哈。

 

好了,不囉嗦。

分析過程:

  • 開啓異步代理

  • 初始化excutor和exceptionHandler

  • 定義切面處理

  • 線程處理

開啓異步化支持

@EnableAsync

@EnableAsync是開啓某個模塊的功能加載,之前在《導圖梳理springboot手動、自動裝配,讓springboot不再難懂》介紹過,@EnableXXX一般都有兩種用法,一種直接引入配置,一種可以通過註解的元數據選擇需要導入的配置。這裏的@EnableAsync明顯屬於第二種。

 
  1.  

    @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.  

    /*
    
    * 關鍵點:
    
    * 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.executorthis.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思維導圖,給我點個在看或者轉發一下,萬分感謝哈!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章