你好,我是猿java。
Spring @Async
注解提供了一个非常简单而且强大的机制来支持异步方法的执行。如果将方法标记为@Async
,Spring会在后台线程中异步执行该方法,而不会阻塞调用该方法的线程。这对于提高应用程序的响应性和性能是非常有用的,尤其是在处理I/O密集型操作时。这篇文章,我们来深度剖析 Spring @Async
的工作原理!
- 原理概述 {#1-原理概述} =================
使用@Async
注解时,Spring 借助 AOP(面向切面编程)实现异步执行,具体来说,@Async
的工作原理主要包括以下几个步骤:
-
代理对象创建 :Spring 使用动态代理创建被注解方法的代理对象。只有与代理对象交互时,
@Async
注解才会起作用。 -
线程池配置 :异步方法调用通过 Spring 提供的
TaskExecutor
(如SimpleAsyncTaskExecutor
,ThreadPoolTaskExecutor
等)来实现多线程处理。开发者可以自定义线程池设置,以适应不同的使用场景。 -
方法执行 :当调用被
@Async
注解的方法时,Spring 将检测到这个注解,然后将方法的调用委托给一个线程池中的线程。在这个线程执行完成后,控制权就会返回到调用线程,不会被阻塞。 -
核心代码分析 {#2-核心代码分析} =====================
下面我们深入探讨@Async
的几个核心类的实现细节。
2.1 @Async
注解 {#2-1-Async-注解}
@Async
注解的定义非常简单,位于org.springframework.scheduling.annotation
包中:
|-------------------|--------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Async { String value() default ""; }
|
通过上面的源码可以看出:@Async
注解只支持放在方法上,并可以指定一个可选的线程池名称。
2.2 AsyncConfiguration
类 {#2-2-AsyncConfiguration类}
要启用异步处理功能,我们需要有一个配置类或在Spring Boot应用程序中使用@EnableAsync
注解。这个注解会触发 Spring的异步支持机制。
|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration @EnableAsync public class AsyncConfig extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } }
|
在这个示例中,我们扩展了AsyncConfigurerSupport
类,并重写了getAsyncExecutor
方法来提供自定义的线程池。
2.3 Proxy 生成 {#2-3-Proxy-生成}
Spring 通过 AOP 动态代理机制处理 @Async
注解。具体过程如下:
- Spring 在创建代理对象时,检查被注解的方法。
- 如果发现方法上有
@Async
注解,Spring 将为这个方法生成一个增强版本,以确保调用被转发到线程池中的一个工作线程。
通常,Spring 会使用 JDK 动态代理或者 CGLIB 代理。JDK 代理基于接口创建代理实例,而 CGLIB 可以基于类创建代理实例。
2.4 异步方法的调用 {#2-4-异步方法的调用}
以下是 @Async
方法的简单示例:
|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7
| @Service public class MyAsyncService { @Async public void asyncMethod() { System.out.println("Executing in " + Thread.currentThread().getName()); } }
|
调用 asyncMethod()
方法时,控制将立即返回,不会阻塞。实际方法将在其他线程中执行。
2.5 AsyncExecutionInterceptor
{#2-5-AsyncExecutionInterceptor}
AsyncExecutionInterceptor
类是 Spring 处理异步执行的核心部分。它实现了 MethodInterceptor
接口,能够拦截方法调用,进行异步执行处理。
|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| public class AsyncExecutionInterceptor extends AbstractAsyncExecutionInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { return doInvoke(invocation); } }
|
在 invoke
方法中,doInvoke
方法会被调用,负责具体的执行逻辑。
3.示例 {#3-示例}
为了更好地理解 @Async
的使用,我们通过一个完整的示例来演示如何使用 Spring @Async
注解实现异步方法调用,示例将包含以下部分:
- Spring Boot 项目结构。
@Async
注解的实现和配置。- 异步方法的调用示例。
- 运行时的输出示例。
3.1 创建 Spring Boot 项目 {#3-1-创建-Spring-Boot-项目}
假设你使用 Spring Boot 创建项目,可以创建一个新的 Gradle 或 Maven 项目,添加以下依赖项到 pom.xml
(如果使用 Maven):
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
3.2 配置异步支持 {#3-2-配置异步支持}
创建一个配置类来启用异步支持,使用 @EnableAsync
注解。
|------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @Configuration @EnableAsync public class AsyncConfig { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(2); executor.setMaxPoolSize(5); executor.setQueueCapacity(10); executor.setThreadNamePrefix("Async-"); executor.initialize(); return executor; } }
|
3.3 创建异步服务类 {#3-3-创建异步服务类}
接下来,创建一个服务类,其中将包含异步方法。该方法将模拟一些耗时的操作。
|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class MyAsyncService { @Async("taskExecutor") public void asyncMethod() { System.out.println("Executing async method: " + Thread.currentThread().getName()); try { // 模拟耗时的操作 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Async method execution finished: " + Thread.currentThread().getName()); } }
|
3.4 创建控制器类 {#3-4-创建控制器类}
创建一个控制器类,调用异步服务中的方法:
|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyAsyncController { @Autowired private MyAsyncService myAsyncService; @GetMapping("/asyncTest") public String callAsync() { System.out.println("Calling async method"); myAsyncService.asyncMethod(); return "Async method called!"; } }
|
3.5 主应用程序类 {#3-5-主应用程序类}
创建 Spring Boot 启动类,用于启动应用程序:
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10
| import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AsyncApplication { public static void main(String[] args) { SpringApplication.run(AsyncApplication.class, args); } }
|
3.6 运行应用程序 {#3-6-运行应用程序}
启动 Spring Boot 应用程序,在浏览器中访问以下 URL:
|-----------|-----------------------------------------|
| 1
| http://localhost:8080/asyncTest
|
输出结果为:
|---------------|-------------------------------------------------------------------------------------------------------|
| 1 2 3
| Calling async method Executing async method: Async-1 Async method execution finished: Async-1
|
在浏览器中,页面将返回 "Async method called!" 的信息,而不会等待 asyncMethod
完成执行。这表示 asyncMethod
在另一个线程上异步执行。
- 总结 {#4-总结} =============
通过以上分析,我们可以看到 Spring 的@Async
提供了异步编程的简便机制。它的实现依赖于 AOP代理,以及可配置的线程池。透过这些机制,Spring 能够将对异步方法的调用转发到后台线程中执行,同时保证主线程不会被阻塞。
- 学习交流 {#5-学习交流} =================