@Async 是 Spring 3.0 提供的一個(gè)注解,用于標(biāo)識(shí)某類(下的公共方法)或某方法會(huì)執(zhí)行異步調(diào)用。
接下來(lái),我們來(lái)看下 @Async 的基本使用和實(shí)現(xiàn)原理。
@Async 基本使用可以分為以下 3 步:
以 Spring Boot 項(xiàng)目為例,我們首先需要在 Spring Boot 的啟動(dòng)類,也就是帶有@SpringBootApplication 注解的類上添加 @EnableAsync 注解,以開(kāi)啟異步方法執(zhí)行的支持,如下代碼所示:
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication@EnableAsyncpublic class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); }}
創(chuàng)建異步方法是在需要異步執(zhí)行的方法上添加 @Async 注解,這個(gè)方法一定是要放在被 IoC 容器管理的 Bean 中,只有被 IoC 管理的類才能實(shí)現(xiàn)異步調(diào)用,例如在帶有 @Service 注解的類中創(chuàng)建異步方法:
import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncService { @Async public void performAsyncTask() { // 這里放置需要異步執(zhí)行的代碼 System.out.println("異步任務(wù)正在執(zhí)行,當(dāng)前線程:" + Thread.currentThread().getName()); }}
在其他類或方法中,通過(guò)注入這個(gè)服務(wù)類的實(shí)例來(lái)調(diào)用異步方法。注意,直接在同一個(gè)類內(nèi)部調(diào)用不會(huì)觸發(fā)異步行為,必須通過(guò)注入的實(shí)例調(diào)用,使用 new 創(chuàng)建的對(duì)象也不能進(jìn)行異步方法調(diào)用,具體實(shí)現(xiàn)代碼如下:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class MyController { @Autowired private AsyncService asyncService; @GetMapping("/startAsync") public String startAsyncTask() { asyncService.performAsyncTask(); return "異步任務(wù)已啟動(dòng)"; }}
簡(jiǎn)單來(lái)說(shuō),@Async 注解是由 AOP(面向切面)實(shí)現(xiàn)的,具體來(lái)說(shuō),它是由 AsyncAnnotationAdvisor 這個(gè)切面類來(lái)實(shí)現(xiàn)的。
在 AsyncAnnotationAdvisor 中,會(huì)使用 AsyncExecutionInterceptor 來(lái)處理 @Async 注解,它會(huì)在被 @Async 注解標(biāo)識(shí)的方法被調(diào)用時(shí),創(chuàng)建一個(gè)異步代理對(duì)象來(lái)執(zhí)行方法。這個(gè)異步代理對(duì)象會(huì)在一個(gè)新的線程中調(diào)用被 @Async 注解標(biāo)識(shí)的方法,從而實(shí)現(xiàn)方法的異步執(zhí)行。
在 AsyncExecutionInterceptor 中,核心方法是 getDefaultExecutor 方法,使用此方法來(lái)獲取一個(gè)線程池來(lái)執(zhí)行被 @Async 注解修飾的方法,它的實(shí)現(xiàn)源碼如下:
@Nullableprotected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) { Executor defaultExecutor = super.getDefaultExecutor(beanFactory); return (Executor)(defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());}
此方法實(shí)現(xiàn)比較簡(jiǎn)單,它是先嘗試調(diào)用父類 AsyncExecutionAspectSupport#getDefaultExecutor 方法獲取線程池,如果父類方法獲取不到線程池再用創(chuàng)建 SimpleAsyncTaskExecutor 對(duì)象作為 Async 的線程池返回。
而 SimpleAsyncTaskExecutor 中在執(zhí)行任務(wù)時(shí)是這樣的:
protected void doExecute(Runnable task) { this.newThread(task).start();}
可以看出,在 Spring 框架中如果使用默認(rèn)的 @Async 注解,它的執(zhí)行比較簡(jiǎn)單粗暴,并沒(méi)有使用線程池,而是每次創(chuàng)建線程來(lái)執(zhí)行,所以在 Spring 框架中是不能直接使用 @Async 注解的,需要使用 @Async 注解搭配自定義的線程池,既實(shí)現(xiàn) AsyncConfigurer 接口來(lái)提供自定義的 ThreadPoolTaskExecutor 來(lái)創(chuàng)建線程池,以確保 @Async 能真正的使用線程池來(lái)執(zhí)行異步任務(wù)。
然而,在 Spring Boot 中,因?yàn)樵诳蚣軉?dòng)時(shí),自動(dòng)注入了 ThreadPoolTaskExecutor,如下源碼所示:
@ConditionalOnClass({ThreadPoolTaskExecutor.class})@AutoConfiguration@EnableConfigurationProperties({TaskExecutionProperties.class})@Import({TaskExecutorConfigurations.ThreadPoolTaskExecutorBuilderConfiguration.class, TaskExecutorConfigurations.TaskExecutorBuilderConfiguration.class, TaskExecutorConfigurations.SimpleAsyncTaskExecutorBuilderConfiguration.class, TaskExecutorConfigurations.TaskExecutorConfiguration.class})public class TaskExecutionAutoConfiguration { public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor"; public TaskExecutionAutoConfiguration() { }}
具體的構(gòu)建細(xì)節(jié)源碼如下:
@Bean@ConditionalOnMissingBean({TaskExecutorBuilder.class, ThreadPoolTaskExecutorBuilder.class})ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<ThreadPoolTaskExecutorCustomizer> threadPoolTaskExecutorCustomizers, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) { TaskExecutionProperties.Pool pool = properties.getPool(); ThreadPoolTaskExecutorBuilder builder = new ThreadPoolTaskExecutorBuilder(); builder = builder.queueCapacity(pool.getQueueCapacity()); builder = builder.corePoolSize(pool.getCoreSize()); builder = builder.maxPoolSize(pool.getMaxSize()); builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()); builder = builder.keepAlive(pool.getKeepAlive()); TaskExecutionProperties.Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); Stream var10001 = threadPoolTaskExecutorCustomizers.orderedStream(); Objects.requireNonNull(var10001); builder = builder.customizers(var10001::iterator); builder = builder.taskDecorator((TaskDecorator)taskDecorator.getIfUnique()); builder = builder.additionalCustomizers(taskExecutorCustomizers.orderedStream().map(this::adapt).toList()); return builder;}
因此在 Spring Boot 框架中可以直接使用 @Async 注解,無(wú)需擔(dān)心它每次都會(huì)創(chuàng)建線程來(lái)執(zhí)行的問(wèn)題。
本文鏈接:http://www.tebozhan.com/showinfo-26-99169-0.html阿里面試:說(shuō)說(shuō)@Async實(shí)現(xiàn)原理?
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: Go語(yǔ)言助力安全測(cè)試:24小時(shí)內(nèi)發(fā)送5億次HTTP/1.1請(qǐng)求
下一篇: 為什么要限流?及常用的限流算法解析