From 3c76a691fd64aac6a15ccc04490408b45770ab3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Thu, 26 Dec 2024 22:09:00 +0800 Subject: [PATCH 1/6] =?UTF-8?q?[docs=20update]@Async=E5=8E=9F=E7=90=86?= =?UTF-8?q?=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/system-design/framework/spring/Async.md | 665 ++++++++++++++++++ .../framework/spring/images/async/async.png | Bin 0 -> 87140 bytes 2 files changed, 665 insertions(+) create mode 100644 docs/system-design/framework/spring/Async.md create mode 100644 docs/system-design/framework/spring/images/async/async.png diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md new file mode 100644 index 00000000000..d23248eacba --- /dev/null +++ b/docs/system-design/framework/spring/Async.md @@ -0,0 +1,665 @@ +# `@Async` 原理分析 + +`@Async` 注解由 Spring 框架提供,被该注解标注的类或方法会在 **异步线程** 中执行。这意味着当方法被调用时,调用者将不会等待该方法执行完成,而是可以继续执行后续的代码。 + +**原理概述:** `@Async` 可以异步执行任务,本质上是使用 **动态代理** 来实现的。通过 Spring 中的后置处理器 `BeanPostProcessor` 为使用 `@Async` 注解的类创建动态代理,之后 `@Async` 注解方法的调用会被动态代理拦截,在拦截器中将方法的执行封装为异步任务提交给线程池处理。 + +开始讲解 `@Async` 的原理之前,我们先来看看`@Async` 使用。 + +## `@Async` 使用步骤 + +`@Async` 注解的使用需要两个步骤: + +1. 在启动类上添加注解 `@EnableAsync` ,开启异步任务。 +2. 在需要异步执行的方法或类上添加注解 `@Async` 。 + +## `@Async` 使用建议 + +### 自定义线程池 + +如果没有显式地配置线程池,Spring Boot 可能会使用默认的 `SimpleAsyncTaskExecutor` 实现。`SimpleAsyncTaskExecutor` 本质上不算是一个真正的线程池,因为它对于每个请求都会启动一个新线程而不重用现有线程,这会带来一些潜在的问题,例如资源消耗过大。 + +为什么说是可能呢?因为,这只是没有显示配置线程池中的一种情况,还可能会存在一些其他情况,但都或多或少存在一些问题,这里就不细说了,具体可以参考这篇文章:[浅析 Spring 中 Async 注解底层异步线程池原理|得物技术](https://mp.weixin.qq.com/s/FySv5L0bCdrlb5MoSfQtAA)。 + +一定要显式配置一个线程池,推荐`ThreadPoolTaskExecutor`。并且,还可以根据任务的性质和需求,为不同的异步方法指定不同的线程池。 + +```java +@Configuration +@EnableAsync +public class AsyncConfig { + + @Bean(name = "executor1") + public Executor executor1() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(3); + executor.setMaxPoolSize(5); + executor.setQueueCapacity(50); + executor.setThreadNamePrefix("AsyncExecutor1-"); + executor.initialize(); + return executor; + } + + @Bean(name = "executor2") + public Executor executor2() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(2); + executor.setMaxPoolSize(4); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("AsyncExecutor2-"); + executor.initialize(); + return executor; + } +} +``` + +`@Async` 注解中指定线程池的 Bean 名称: + +```java +@Service +public class AsyncService { + + @Async("executor1") + public void performTask1() { + // 任务1的逻辑 + System.out.println("Executing Task1 with Executor1"); + } + + @Async("executor2") + public void performTask2() { + // 任务2的逻辑 + System.out.println("Executing Task2 with Executor2"); + } +} +``` + +### 避免 @Async 注解失效 + +`@Async` 注解会在以下几个场景失效,需要注意: + +**1、同一类中调用异步方法** + +如果你在同一个类内部调用一个`@Async`注解的方法,那这个方法将不会异步执行。 + +```java +@Service +public class MyService { + + public void myMethod() { + // 直接通过 this 引用调用,绕过了 Spring 的代理机制,异步执行失效 + asyncMethod(); + } + + @Async + public void asyncMethod() { + // 异步执行的逻辑 + } +} +``` + +这是因为 Spring 的异步机制是通过 **代理** 实现的,而在同一个类内部的方法调用会绕过 Spring 的代理机制,也就是绕过了代理对象,直接通过 this 引用调用的。由于没有经过代理,所有的代理相关的处理(即将任务提交线程池异步执行)都不会发生。 + +为了避免这个问题,比较推荐的做法是将异步方法移至另一个 Spring Bean 中。 + +```java +@Service +public class AsyncService { + @Async + public void asyncMethod() { + // 异步执行的逻辑 + } +} + +@Service +public class MyService { + @Autowired + private AsyncService asyncService; + + public void myMethod() { + asyncService.asyncMethod(); + } +} +``` + +**2、使用 static 关键字修饰异步方法** + +如果`@Async`注解的方法被 `static` 关键字修饰,那这个方法将不会异步执行。 + +这是因为 Spring 的异步机制是通过代理实现的,由于静态方法不属于实例而是属于类且不参与继承,Spring 的代理机制(无论是基于 JDK 还是 CGLIB)无法拦截静态方法来提供如异步执行这样的增强功能。 + +篇幅问题,这里没有进一步详细介绍,不了解的代理机制的朋友,可以看看我写的 [Java 代理模式详解](https://javaguide.cn/java/basis/proxy.html)这篇文章。 + +如果你需要异步执行一个静态方法的逻辑,可以考虑设计一个非静态的包装方法,这个包装方法使用 `@Async` 注解,并在其内部调用静态方法 + +```java +@Service +public class AsyncService { + + @Async + public void asyncWrapper() { + // 调用静态方法 + SClass.staticMethod(); + } +} + +public class SClass { + public static void staticMethod() { + // 执行一些操作 + } +} +``` + +**3、忘记开启异步支持** + +Spring Boot 默认情况下不启用异步支持,确保在主配置类 `Application` 上添加`@EnableAsync`注解以启用异步功能。 + +```java +@SpringBootApplication +@EnableAsync +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + +**4、`@Async` 注解的方法所在的类必须是 Spring Bean** + +`@Async` 注解的方法必须位于 Spring 管理的 Bean 中,只有这样,Spring 才能在创建 Bean 时应用代理,代理能够拦截方法调用并实现异步执行的逻辑。如果该方法不在 Spring 管理的 bean 中,Spring 就无法创建必要的代理,`@Async` 注解就不会产生任何效果。 + +### 返回值类型 + +建议将 `@Async` 注解方法的返回值类型定义为 `void` 和 `Future` 。 + +- 如果不需要获取异步方法返回的结果,将返回值类型定义为 `void` 。 +- 如果需要获取异步方法返回的结果,将返回值类型定义为 `Future`(例如`CompletableFuture` 、 `ListenableFuture` )。 + +如果将 `@Async` 注解方法的返回值定义为其他类型(如 `Object` 、 `String` 等等),则无法获取方法返回值。 + +这种设计符合异步编程的基本原则,即调用者不应立即期待一个结果,而是应该能够在未来某个时间点获取结果。如果返回类型是 `Future`,调用者可以使用这个返回的 `Future` 对象来查询任务的状态,取消任务,或者在任务完成时获取结果。 + +### 处理异步方法中的异常 + +异步方法中抛出的异常默认不会被调用者捕获。为了管理这些异常,建议使用`CompletableFuture`的异常处理功能,或者配置一个全局的`AsyncUncaughtExceptionHandler`来处理没有正确捕获的异常。 + +```java +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer{ + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new CustomAsyncExceptionHandler(); + } + +} + +// 自定义异常处理器 +class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { + + @Override + public void handleUncaughtException(Throwable ex, Method method, Object... params) { + // 日志记录或其他处理逻辑 + } +} +``` + +### 未考虑事务管理 + +`@Async`注解的方法需要事务支持时,务必在该异步方法上独立使用。 + +```java +@Service +public class AsyncTransactionalService { + + @Async + // Propagation.REQUIRES_NEW 表示 Spring 在执行异步方法时开启一个新的、与当前事务无关的事务 + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void asyncTransactionalMethod() { + // 这里的操作会在新的事务中执行 + // 执行一些数据库操作 + } +} +``` + +### 未指定异步方法执行顺序 + +`@Async`注解的方法执行是非阻塞的,它们可能以任意顺序完成。如果需要按照特定的顺序处理结果,你可以将方法的返回值设定为 `Future` 或 `CompletableFuture` ,通过返回值对象来实现一个方法在另一个方法完成后再执行。 + +```java +@Async +public CompletableFuture fetchDataAsync() { + return CompletableFuture.completedFuture("Data"); +} + +@Async +public CompletableFuture processDataAsync(String data) { + return CompletableFuture.supplyAsync(() -> "Processed " + data); +} +``` + +`processDataAsync` 方法在 `fetchDataAsync`后执行: + +```java +CompletableFuture dataFuture = asyncService.fetchDataAsync(); +dataFuture.thenCompose(data -> asyncService.processDataAsync(data)) + .thenAccept(result -> System.out.println(result)); +``` + +## `@Async` 原理分析 + +### 开启异步 + +使用 `@Async` 之前,需要在启动类上添加 `@EnableAsync` 来开启异步,`@EnableAsync` 注解如下: + +```JAVA +// 省略其他注解 ... +@Import(AsyncConfigurationSelector.class) +public @interface EnableAsync { /* ... */ } +``` + +在 `@EnableAsync` 注解上通过 `@Import` 注解引入了 `AsyncConfigurationSelector` ,因此 Spring 会去加载通过 `@Import` 注解引入的类。 + +`AsyncConfigurationSelector` 类实现了 `ImportSelector` 接口,因此在该类中会重写 `selectImports()` 方法来自定义加载 Bean 的逻辑,如下: + +```JAVA +public class AsyncConfigurationSelector extends AdviceModeImportSelector { + @Override + @Nullable + public String[] selectImports(AdviceMode adviceMode) { + switch (adviceMode) { + // 基于 JDK 代理织入的通知 + case PROXY: + return new String[] {ProxyAsyncConfiguration.class.getName()}; + // 基于 AspectJ 织入的通知 + case ASPECTJ: + return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME}; + default: + return null; + } + } +} +``` + +在 `selectImports()` 方法中,会根据通知的不同类型来选择加载不同的类,其中 `adviceMode` 默认值为 `PROXY` 。 + +这里以基于 JDK 代理的通知为例,此时会加载 `ProxyAsyncConfiguration` 类,如下: + +```JAVA +@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() { + // ... + + // 加载后置处理器 + AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor(); + + // ... + return bpp; + } +} +``` + +### 后置处理器 + +在 `ProxyAsyncConfiguration` 类中,会通过 `@Bean` 注解加载一个后置处理器 `AsyncAnnotationBeanPostProcessor` ,这个后置处理器是使 `@Async` 注解起作用的关键。 + +如果某一个类或者方法上使用了 `@Async` 注解,`AsyncAnnotationBeanPostProcessor` 处理器就会为该类创建一个动态代理。 + +该类的方法在执行时,会被代理对象的拦截器所拦截,其中被 `@Async` 注解标记的方法会异步执行。 + +`AsyncAnnotationBeanPostProcessor` 代码如下: + +```JAVA +public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor { + @Override + public void setBeanFactory(BeanFactory beanFactory) { + super.setBeanFactory(beanFactory); + · + // 创建 Advisor + AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler); + if (this.asyncAnnotationType != null) { + advisor.setAsyncAnnotationType(this.asyncAnnotationType); + } + advisor.setBeanFactory(beanFactory); + this.advisor = advisor; + } +} +``` + +`AsyncAnnotationBeanPostProcessor` 的父类实现了 `BeanFactoryAware` 接口,因此在该类中重写了 `setBeanFactory()` 方法作为扩展点,来加载 `AsyncAnnotationAdvisor` 。 + +#### 创建 Advisor + +`Advisor` 是 `Spring AOP` 对 `Advice` 和 `Pointcut` 的抽象。`Advice` 为执行的通知逻辑,`Pointcut` 为通知执行的切入点。 + +在后置处理器 `AsyncAnnotationBeanPostProcessor` 中会去创建 `AsyncAnnotationAdvisor` , 在它的构造方法中,会构建对应的 `Advice` 和 `Pointcut` ,如下: + +```JAVA +public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware { + + private Advice advice; + private Pointcut pointcut; + + // 构造方法 + public AsyncAnnotationAdvisor(/* 参数省略 */) { + // 1、构建 Advice + this.advice = buildAdvice(executor, exceptionHandler); + // 2、构建 Pointcut + this.pointcut = buildPointcut(asyncAnnotationTypes); + } + + // 构建 Advice + protected Advice buildAdvice(/* 参数省略 */) { + // 创建 AnnotationAsyncExecutionInterceptor + AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null); + interceptor.configure(executor, exceptionHandler); + return interceptor; + } + + // 构建 Pointcut + protected Pointcut buildPointcut(Set> asyncAnnotationTypes) { + ComposablePointcut result = null; + for (Class asyncAnnotationType : asyncAnnotationTypes) { + // 1、类匹配(类上有对应注解的话,该类的所有方法都匹配) + Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true); + // 2、方法匹配(只有方法上有对应注解才匹配) + Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true); + if (result == null) { + result = new ComposablePointcut(cpc); + } + else { + result.union(cpc); + } + // 3、使用 union 取 cpc 和 mpc 两个 Pointcut 的并集。 + result = result.union(mpc); + } + return (result != null ? result : Pointcut.TRUE); + } + +} + +``` + +`AsyncAnnotationAdvisor ` 的核心在于构建 `Advice` 和 `Pointcut` : + +- 构建 `Advice` :会创建 `AnnotationAsyncExecutionInterceptor` 拦截器,在拦截器的 `invoke()` 方法中会执行通知的逻辑。 +- 构建 `Pointcut` :由 `ClassFilter` 和 `MethodMatcher` 组成,用于匹配哪些方法需要执行通知( `Advice` )的逻辑。 + +#### 后置处理逻辑 + +`AsyncAnnotationBeanPostProcessor` 后置处理器中实现的 `postProcessAfterInitialization()` 方法在其父类 `AbstractAdvisingBeanPostProcessor` 中,在 `Bean` 初始化之后,会进入到 `postProcessAfterInitialization()` 方法进行后置处理。 + +在后置处理方法中,会判断 `Bean` 是否符合后置处理器中 `Advisor` 通知的条件,如果符合,则创建代理对象。如下: + +```JAVA +// AbstractAdvisingBeanPostProcessor +public Object postProcessAfterInitialization(Object bean, String beanName) { + if (this.advisor == null || bean instanceof AopInfrastructureBean) { + return bean; + } + if (bean instanceof Advised) { + Advised advised = (Advised) bean; + if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) { + if (this.beforeExistingAdvisors) { + advised.addAdvisor(0, this.advisor); + } + else { + advised.addAdvisor(this.advisor); + } + return bean; + } + } + // 判断给定的 Bean 是否符合后置处理器中 Advisor 通知的条件,符合的话,就创建代理对象。 + if (isEligible(bean, beanName)) { + ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName); + if (!proxyFactory.isProxyTargetClass()) { + evaluateProxyInterfaces(bean.getClass(), proxyFactory); + } + // 添加 Advisor。 + proxyFactory.addAdvisor(this.advisor); + customizeProxyFactory(proxyFactory); + // 返回代理对象。 + return proxyFactory.getProxy(getProxyClassLoader()); + } + return bean; +} +``` + +### `@Async` 注解方法的拦截 + +`@Async` 注解方法的执行会在 `AnnotationAsyncExecutionInterceptor` 中被拦截,在 `invoke()` 方法中执行拦截器的逻辑。此时会将 `@Async` 注解标注的方法封装为异步任务,交给执行器来执行。 + +`invoke()` 方法在 `AnnotationAsyncExecutionInterceptor` 的父类 `AsyncExecutionInterceptor` 中定义,如下: + +```JAVA +public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered { + @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); + + // 1、确定异步任务执行器 + AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod); + + // 2、将要执行的方法封装为 Callable 异步任务 + Callable task = () -> { + try { + // 2.1、执行方法 + Object result = invocation.proceed(); + // 2.2、如果方法返回值是 Future 类型,阻塞等待结果 + 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; + }; + // 3、提交任务 + return doSubmit(task, executor, invocation.getMethod().getReturnType()); + } +} +``` + +在 `invoke()` 方法中,主要有 3 个步骤: + +1. 确定执行异步任务的执行器。 +2. 将 `@Async` 注解标注的方法封装为 `Callable` 异步任务。 +3. 将任务提交给执行器执行。 + +#### 1、获取异步任务执行器 + +在 `determineAsyncExecutor()` 方法中,会获取异步任务的执行器(即执行异步任务的 **线程池** )。代码如下: + +```JAVA +// 确定异步任务的执行器 +protected AsyncTaskExecutor determineAsyncExecutor(Method method) { + // 1、先从缓存中获取。 + AsyncTaskExecutor executor = this.executors.get(method); + if (executor == null) { + Executor targetExecutor; + // 2、获取执行器的限定符。 + String qualifier = getExecutorQualifier(method); + if (StringUtils.hasLength(qualifier)) { + // 3、根据限定符获取对应的执行器。 + targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier); + } + else { + // 4、如果没有限定符,则使用默认的执行器。即 Spring 提供的默认线程池:SimpleAsyncTaskExecutor。 + targetExecutor = this.defaultExecutor.get(); + } + if (targetExecutor == null) { + return null; + } + // 5、将执行器包装为 TaskExecutorAdapter 适配器。 + // TaskExecutorAdapter 是 Spring 对于 JDK 线程池做的一层抽象,还是继承自 JDK 的线程池 Executor。这里可以不用管太多,只要知道它是线程池就可以了。 + executor = (targetExecutor instanceof AsyncListenableTaskExecutor ? + (AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor)); + this.executors.put(method, executor); + } + return executor; +} +``` + +在 `determineAsyncExecutor()` 方法中确定了异步任务的执行器(线程池),主要是通过 `@Async` 注解的 `value` 值来获取执行器的限定符,根据限定符再去 `BeanFactory` 中查找对应的执行器就可以了。 + +如果在 `@Async` 注解中没有指定线程池,则会通过 `this.defaultExecutor.get()` 来获取默认的线程池,其中 `defaultExecutor` 在下边方法中进行赋值: + +```JAVA +// AsyncExecutionInterceptor +protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) { + // 1、尝试从 beanFactory 中获取线程池。 + Executor defaultExecutor = super.getDefaultExecutor(beanFactory); + // 2、如果 beanFactory 中没有,则创建 SimpleAsyncTaskExecutor 线程池。 + return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor()); +} +``` + +其中 `super.getDefaultExecutor()` 会在 `beanFactory` 中尝试获取 `Executor` 类型的线程池。代码如下: + +```JAVA +protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) { + if (beanFactory != null) { + try { + // 1、从 beanFactory 中获取 TaskExecutor 类型的线程池。 + return beanFactory.getBean(TaskExecutor.class); + } + catch (NoUniqueBeanDefinitionException ex) { + try { + // 2、如果有多个,则尝试从 beanFactory 中获取执行名称的 Executor 线程池。 + return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); + } + catch (NoSuchBeanDefinitionException ex2) { + if (logger.isInfoEnabled()) { + // ... + } + } + } + catch (NoSuchBeanDefinitionException ex) { + try { + // 3、如果没有,则尝试从 beanFactory 中获取执行名称的 Executor 线程池。 + return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); + } + catch (NoSuchBeanDefinitionException ex2) { + // ... + } + } + } + return null; +} +``` + +在 `getDefaultExecutor()` 中,如果从 `beanFactory` 获取线程池失败的话,则会创建 `SimpleAsyncTaskExecutor` 线程池。 + +该线程池的在每次执行异步任务时,都会创建一个新的线程去执行任务,并不会对线程进行复用,从而导致异步任务执行的开销很大。一旦在 `@Async` 注解标注的方法某一瞬间并发量剧增,应用就会大量创建线程,从而影响服务质量甚至出现服务不可用。 + +同一时刻如果向 `SimpleAsyncTaskExecutor` 线程池提交 10000 个任务,那么该线程池就会创建 10000 个线程,其的 `execute()` 方法如下: + +```JAVA +// SimpleAsyncTaskExecutor:execute() 内部会调用 doExecute() +protected void doExecute(Runnable task) { + // 创建新线程 + Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task)); + thread.start(); +} +``` + +**建议:在使用 `@Async` 时需要自己指定线程池,避免 Spring 默认线程池带来的风险。** + +在 `@Async` 注解中的 `value` 指定了线程池的限定符,根据限定符可以获取 **自定义的线程池** 。获取限定符的代码如下: + +```JAVA +// AnnotationAsyncExecutionInterceptor +protected String getExecutorQualifier(Method method) { + // 获取 Async 注解。 + Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class); + if (async == null) { + async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class); + } + // 获取注解的 value 值。 + return (async != null ? async.value() : null); +} +``` + +#### 2、将方法封装为异步任务 + +在 `invoke()` 方法获取执行器之后,会将方法封装为异步任务,代码如下: + +```JAVA +// 2、将要执行的方法封装为 Callable 异步任务 +Callable task = () -> { + try { + // 2.1、执行方法 + Object result = invocation.proceed(); + // 2.2、如果方法返回值是 Future 类型,阻塞等待结果 + 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; +}; +``` + +相比于 `Runnable` ,`Callable` 可以返回结果,并且抛出异常。 + +将 `invocation.proceed()` 的执行(原方法的执行)封装为 `Callable` 异步任务。这里仅仅当 `result` (方法返回值)类型为 `Future` 才返回,如果是其他类型则直接返回 `null` 。 + +因此使用 `@Async` 注解标注的方法如果使用 `Future` 类型之外的返回值,则无法获取方法的执行结果。 + +#### 3、提交异步任务 + +在 `AsyncExecutionInterceptor # invoke()` 中将要执行的方法封装为 Callable 任务之后,就会将任务交给执行器来执行。提交相关的代码如下: + +```JAVA +protected Object doSubmit(Callable task, AsyncTaskExecutor executor, Class returnType) { + // 方法返回值是 CompletableFuture 类型 + if (CompletableFuture.class.isAssignableFrom(returnType)) { + return CompletableFuture.supplyAsync(() -> { + try { + return task.call(); + } + catch (Throwable ex) { + throw new CompletionException(ex); + } + }, executor); + } + // 方法返回值是 ListenableFuture 类型 + else if (ListenableFuture.class.isAssignableFrom(returnType)) { + return ((AsyncListenableTaskExecutor) executor).submitListenable(task); + } + // 方法返回值是 Future 类型 + else if (Future.class.isAssignableFrom(returnType)) { + return executor.submit(task); + } + // 方法返回值是 void + else { + executor.submit(task); + return null; + } +} +``` + +在 `doSubmit()` 方法中,会根据 `@Async` 注解标注方法的返回值不同,来选择不同的任务提交方式,最后任务会由执行器(线程池)执行。 + +### `@Async` 原理总结 + +![Async原理总结](./async.png) + +理解 `@Async` 原理的核心在于理解 `@EnableAsync` 注解,该注解开启了异步任务的功能。 + +主要流程如上图,会通过后置处理器来创建代理对象,之后代理对象中 `@Async` 方法的执行会走到 `Advice` 内部的拦截器中,之后将方法封装为异步任务,并提交线程池进行处理。 diff --git a/docs/system-design/framework/spring/images/async/async.png b/docs/system-design/framework/spring/images/async/async.png new file mode 100644 index 0000000000000000000000000000000000000000..6b68fd35084055209803ae107d4bdfce8d27b43f GIT binary patch literal 87140 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�O>p2=6hj%{2J^aYWdnpFI-?TfB(nu!w)B3icnR# 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 Date: Thu, 26 Dec 2024 22:18:24 +0800 Subject: [PATCH 2/6] =?UTF-8?q?[docs=20update]=E6=9B=B4=E6=94=B9=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/system-design/framework/spring/Async.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md index d23248eacba..c2e1e701cb0 100644 --- a/docs/system-design/framework/spring/Async.md +++ b/docs/system-design/framework/spring/Async.md @@ -658,7 +658,7 @@ protected Object doSubmit(Callable task, AsyncTaskExecutor executor, Cla ### `@Async` 原理总结 -![Async原理总结](./async.png) +![Async原理总结](./images/async.png) 理解 `@Async` 原理的核心在于理解 `@EnableAsync` 注解,该注解开启了异步任务的功能。 From d803817f9e8c66351e07fb06bce0a8cfd1081e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Thu, 26 Dec 2024 23:09:39 +0800 Subject: [PATCH 3/6] =?UTF-8?q?[docs=20update]=E4=BF=AE=E6=94=B9=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/system-design/framework/spring/Async.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md index c2e1e701cb0..e3bfe7f9637 100644 --- a/docs/system-design/framework/spring/Async.md +++ b/docs/system-design/framework/spring/Async.md @@ -658,7 +658,7 @@ protected Object doSubmit(Callable task, AsyncTaskExecutor executor, Cla ### `@Async` 原理总结 -![Async原理总结](./images/async.png) +![Async原理总结](./images/async/async.png) 理解 `@Async` 原理的核心在于理解 `@EnableAsync` 注解,该注解开启了异步任务的功能。 From 1d68b14cdbd022a13b7f452862ac70f117106097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Thu, 26 Dec 2024 23:14:08 +0800 Subject: [PATCH 4/6] =?UTF-8?q?[docs=20update]=E5=AE=8C=E5=96=84=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E6=B1=A0=E8=8E=B7=E5=8F=96=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/system-design/framework/spring/Async.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md index e3bfe7f9637..8495ae71d93 100644 --- a/docs/system-design/framework/spring/Async.md +++ b/docs/system-design/framework/spring/Async.md @@ -17,9 +17,9 @@ ### 自定义线程池 -如果没有显式地配置线程池,Spring Boot 可能会使用默认的 `SimpleAsyncTaskExecutor` 实现。`SimpleAsyncTaskExecutor` 本质上不算是一个真正的线程池,因为它对于每个请求都会启动一个新线程而不重用现有线程,这会带来一些潜在的问题,例如资源消耗过大。 +如果没有显式地配置线程池,在 `@Async` 底层会先在 `BeanFactory` 中尝试获取线程池,如果获取不到,则会创建一个 `SimpleAsyncTaskExecutor` 实现。`SimpleAsyncTaskExecutor` 本质上不算是一个真正的线程池,因为它对于每个请求都会启动一个新线程而不重用现有线程,这会带来一些潜在的问题,例如资源消耗过大。 -为什么说是可能呢?因为,这只是没有显示配置线程池中的一种情况,还可能会存在一些其他情况,但都或多或少存在一些问题,这里就不细说了,具体可以参考这篇文章:[浅析 Spring 中 Async 注解底层异步线程池原理|得物技术](https://mp.weixin.qq.com/s/FySv5L0bCdrlb5MoSfQtAA)。 +具体线程池获取可以参考这篇文章:[浅析 Spring 中 Async 注解底层异步线程池原理|得物技术](https://mp.weixin.qq.com/s/FySv5L0bCdrlb5MoSfQtAA)。 一定要显式配置一个线程池,推荐`ThreadPoolTaskExecutor`。并且,还可以根据任务的性质和需求,为不同的异步方法指定不同的线程池。 From 3b81052f53fd8edb174346f50f2ff8d0a91cb065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Fri, 27 Dec 2024 00:33:08 +0800 Subject: [PATCH 5/6] =?UTF-8?q?[docs=20update]=E6=9B=B4=E6=96=B0=E7=9B=AE?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vuepress/sidebar/index.ts | 1 + docs/system-design/framework/spring/Async.md | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/.vuepress/sidebar/index.ts b/docs/.vuepress/sidebar/index.ts index 575b5aae3d1..4269a60269b 100644 --- a/docs/.vuepress/sidebar/index.ts +++ b/docs/.vuepress/sidebar/index.ts @@ -414,6 +414,7 @@ export default sidebar({ "spring-transaction", "spring-design-patterns-summary", "spring-boot-auto-assembly-principles", + "async", ], }, ], diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md index 8495ae71d93..c751249d871 100644 --- a/docs/system-design/framework/spring/Async.md +++ b/docs/system-design/framework/spring/Async.md @@ -1,8 +1,15 @@ +--- +title: Async 注解原理分析 +category: 框架 +tag: + - Spring +--- + # `@Async` 原理分析 `@Async` 注解由 Spring 框架提供,被该注解标注的类或方法会在 **异步线程** 中执行。这意味着当方法被调用时,调用者将不会等待该方法执行完成,而是可以继续执行后续的代码。 -**原理概述:** `@Async` 可以异步执行任务,本质上是使用 **动态代理** 来实现的。通过 Spring 中的后置处理器 `BeanPostProcessor` 为使用 `@Async` 注解的类创建动态代理,之后 `@Async` 注解方法的调用会被动态代理拦截,在拦截器中将方法的执行封装为异步任务提交给线程池处理。 +**原理介绍:** `@Async` 可以异步执行任务,本质上是使用 **动态代理** 来实现的。通过 Spring 中的后置处理器 `BeanPostProcessor` 为使用 `@Async` 注解的类创建动态代理,之后 `@Async` 注解方法的调用会被动态代理拦截,在拦截器中将方法的执行封装为异步任务提交给线程池处理。 开始讲解 `@Async` 的原理之前,我们先来看看`@Async` 使用。 From 29e40c09e837c32d3f2317cdf35181491ea7a427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Fri, 27 Dec 2024 01:03:38 +0800 Subject: [PATCH 6/6] =?UTF-8?q?[docs=20update]=E5=88=A0=E9=99=A4=E4=B8=80?= =?UTF-8?q?=E7=BA=A7=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/system-design/framework/spring/Async.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/system-design/framework/spring/Async.md b/docs/system-design/framework/spring/Async.md index c751249d871..5d424873435 100644 --- a/docs/system-design/framework/spring/Async.md +++ b/docs/system-design/framework/spring/Async.md @@ -5,8 +5,6 @@ tag: - Spring --- -# `@Async` 原理分析 - `@Async` 注解由 Spring 框架提供,被该注解标注的类或方法会在 **异步线程** 中执行。这意味着当方法被调用时,调用者将不会等待该方法执行完成,而是可以继续执行后续的代码。 **原理介绍:** `@Async` 可以异步执行任务,本质上是使用 **动态代理** 来实现的。通过 Spring 中的后置处理器 `BeanPostProcessor` 为使用 `@Async` 注解的类创建动态代理,之后 `@Async` 注解方法的调用会被动态代理拦截,在拦截器中将方法的执行封装为异步任务提交给线程池处理。