1、前言
在现代Java应用程序中,异步处理是提高性能和响应速度的重要手段之一,比如博主之前分享的【Spring Boot 使用自定义注解和自定义线程池实现异步日志记录】,就是采用了异步处理来实现日志记录,而在Spring Boot中它提供了@Async注解来简化异步编程,今天博主就来和小伙伴们分享本@Async注解的基本使用、实现原理以及应用场景。
2、@Async注解的基本使用
@Async注解用于标注方法,使其在独立的线程中异步执行。Spring Boot提供了一种简单的方法来启用异步方法调用,只需在配置类或主类上添加@EnableAsync注解
❶ 引入依赖
在 Spring Boot 项目 pom.xml 文件中添加必要的依赖:
<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>
启用异步支持
在Spring Boot应用的配置类或主类上启用异步支持 @EnableAsync:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
定义异步方法
使用@Async注解定义异步方法。例如:创建一个服务类AsyncService
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public void asyncMethod() {
try {
Thread.sleep(5000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步方法执行完成");
}
}
调用异步方法
在需要调用异步方法的地方,通过注入AsyncService并调用其异步方法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/async")
public String callAsyncMethod() {
asyncService.asyncMethod();
return "异步方法已调用";
}
}
最后请求访问Controller/api/async , 会发现Controller立即返回响应,而asyncMethod将在独立线程中执行,5秒后控制台输出:异步方法执行完成
3、@Async注解的实现原理
@Async注解的实现依赖于Spring的AOP(面向切面编程)和TaskExecutor
❶ TaskExecutor
Spring 使用TaskExecutor来处理异步任务。默认情况下,Spring Boot使用SimpleAsyncTaskExecutor,但我们也可以自定义TaskExecutor来控制线程池
自定义TaskExecutor
我们可以通过@Bean注解定义自定义的TaskExecutor
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
}
❷ AOP代理
@Async注解通过Spring AOP代理来实现异步调用。当标注为@Async的方法被调用时,Spring AOP会拦截调用并在TaskExecutor的线程池中异步执行该方法
❸ 异步方法返回值
@Async注解的方法可以返回void、Future、CompletableFuture等类型,如下代码
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethodWithReturn() {
try {
Thread.sleep(5000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("异步方法返回结果");
}
}
调用带返回值的异步方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/asyncWithReturn")
public CompletableFuture<String> callAsyncMethodWithReturn() {
return asyncService.asyncMethodWithReturn();
}
}
4、应用场景
@Async注解适用于各种需要异步处理的场景,例如:
❶ 后台任务处理
在Web应用中,有些任务(如发送邮件、生成报告)耗时较长,可以使用@Async异步处理,使用户无需等待任务完成即可获得响应。
❷ 并行处理
对于可以并行处理的任务,如并行数据处理、并行调用多个外部服务,使用@Async可以提高效率。
❸ 提高系统吞吐量
通过异步调用,可以充分利用多线程资源,提高系统的吞吐量和响应速度。
5、常见问题及解决方案
5.1、@Async方法调用无效
如果在同一个类中调用@Async注解的方法,异步调用可能无效。这是因为Spring AOP代理无法拦截同一类中的@Async。
解决方法:将异步方法放到另一个类中,通过依赖注入进行调用
5.2、异常处理
异步方法中的异常不会自动传播到调用方。可以使用CompletableFuture处理异常,见下面演示代码
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethodWithException() {
try {
Thread.sleep(5000); // 模拟耗时操作
throw new RuntimeException("异常发生");
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("异步方法完成");
}
}
处理异常:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/asyncWithException")
public CompletableFuture<String> callAsyncMethodWithException() {
return asyncService.asyncMethodWithException()
.exceptionally(ex -> "处理异常:" + ex.getMessage());
}
}
6、结语
Spring Boot的@Async注解提供了一种简洁且强大的方式来实现异步处理。通过启用异步支持、定义异步方法并自定义TaskExecutor,可以高效地处理各种异步任务。掌握@Async注解的使用和原理,有助于提升应用程序的性能和响应速度。