快速入门

启用异步支持

在 Spring Boot 应用中,首先需要在配置类上添加 @EnableAsync 注解来开启异步功能:

@Configuration

@EnableAsync

public class AsyncConfig {

// 可在此自定义线程池

}

标记异步方法

在需要异步执行的方法上添加 @Async 注解:

@Service

public class NotificationService {

// 无返回值的异步方法

@Async

public void sendEmail(String email) {

// 模拟耗时操作

try {

Thread.sleep(3000);

System.out.println("邮件已发送至: " + email);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

// 有返回值的异步方法

@Async

public Future processData(String input) {

try {

Thread.sleep(2000);

String result = "处理结果: " + input.toUpperCase();

return new AsyncResult<>(result);

} catch (InterruptedException e) {

return new AsyncResult<>("处理失败");

}

}

}

调用异步方法

@RestController

public class DemoController {

@Autowired

private NotificationService notificationService;

@GetMapping("/send")

public String sendEmail() {

notificationService.sendEmail("user@example.com");

return "请求已接受,处理中...";

}

@GetMapping("/process")

public String processData() throws Exception {

Future future = notificationService.processData("hello");

// 执行其他任务...

String result = future.get(); // 阻塞获取结果

return result;

}

}

实现原理

核心机制:AOP 与代理模式

Spring 的 @Async 功能基于 AOP(面向切面编程)和代理模式实现:

启用阶段:@EnableAsync 导入配置,注册 AsyncAnnotationBeanPostProcessor

处理阶段:后处理器检查 Bean 方法上的 @Async 注解,并创建代理对象

执行阶段:代理对象拦截方法调用,将执行提交给 TaskExecutor

源码解析

核心拦截器 AnnotationAsyncExecutionInterceptor 的 invoke 方法:

public Object invoke(final MethodInvocation invocation) throws Throwable {

// 确定使用的执行器

Executor executor = getExecutor(this.beanFactory, invocation.getMethod());

// 将方法调用封装为 Callable 任务

Callable task = () -> {

try {

Object result = invocation.proceed(); // 执行原始方法

if (result instanceof Future) {

return ((Future) result).get();

}

}

catch (Throwable ex) {

handleError(ex, invocation.getMethod(), invocation.getArguments());

}

return null;

};

// 提交给执行器执行

return doSubmit(task, executor, invocation.getMethod().getReturnType());

}

返回值处理逻辑在 doSubmit 方法中:

protected Object doSubmit(Callable 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); // 非Future类型,提交后返回null

return null;

}

}

默认配置

Spring Boot 的自动化配置

Spring Boot 通过 TaskExecutionAutoConfiguration 自动配置线程池,默认参数如下:

配置项 默认值 说明

核心线程数 8 即使空闲也会保留的线程数

最大线程数 Integer.MAX_VALUE 线程池可创建的最大线程数

队列容量 Integer.MAX_VALUE 使用无界LinkedBlockingQueue

线程空闲时间 60秒 超出核心线程数的空闲线程存活时间

线程名称前缀 "task-" 线程名称的前缀

拒绝策略 AbortPolicy 抛出RejectedExecutionException

配置属性映射

Spring Boot 将这些配置映射到 application.properties:

# 线程池配置

spring.task.execution.pool.core-size=8

spring.task.execution.pool.max-size=2147483647

spring.task.execution.pool.queue-capacity=2147483647

spring.task.execution.pool.keep-alive=60s

spring.task.execution.thread-name-prefix=task-

与纯 Spring 的差异

环境 默认执行器 特点 适用场景

纯 Spring SimpleAsyncTaskExecutor 无线程池,每次创建新线程 不适用于生产环境

Spring Boot ThreadPoolTaskExecutor 固定核心线程+无界队列 开发测试环境

最佳实践

1. 自定义线程池配置

生产环境必须自定义线程池参数:

@Configuration

@EnableAsync

public class AsyncConfig {

@Bean(name = "taskExecutor")

public Executor taskExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

// 核心配置

executor.setCorePoolSize(10);

executor.setMaxPoolSize(25);

executor.setQueueCapacity(100); // 使用有界队列

executor.setKeepAliveSeconds(30);

// 线程配置

executor.setThreadNamePrefix("App-Async-");

executor.setThreadPriority(Thread.NORM_PRIORITY);

// 拒绝策略

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

// 关闭设置

executor.setWaitForTasksToCompleteOnShutdown(true);

executor.setAwaitTerminationSeconds(60);

executor.initialize();

return executor;

}

}

2. 异常处理

异步方法中的异常不会自动传播,需要专门处理:

@Configuration

@EnableAsync

public class AsyncConfig implements AsyncConfigurer {

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

return (ex, method, params) -> {

// 记录日志、发送警报等

logger.error("异步方法执行失败: {}.{}", method.getDeclaringClass().getName(), method.getName(), ex);

alertService.sendAlert("异步任务异常", ex.getMessage());

};

}

}

3. 使用 CompletableFuture

Java 8+ 推荐使用 CompletableFuture 作为返回值:

@Async

public CompletableFuture asyncProcess(String input) {

return CompletableFuture.supplyAsync(() -> {

// 业务逻辑

return processInput(input);

}, taskExecutor);

}

4. 实际应用案例

日志记录场景的异步处理:

@Service

public class AuditLogService {

@Async("taskExecutor")

public void logAction(AuditLog log) {

try {

// 模拟耗时的日志存储操作

auditRepository.save(log);

System.out.println("[" + Thread.currentThread().getName() + "] 审计日志已记录: " + log.getAction());

} catch (Exception e) {

System.err.println("记录审计日志失败: " + e.getMessage());

// 可加入重试逻辑

}

}

}

@RestController

public class BusinessController {

@Autowired

private AuditLogService auditLogService;

@PostMapping("/business-action")

public ResponseEntity performBusinessAction(@RequestBody ActionRequest request) {

// 执行核心业务逻辑

BusinessResult result = businessService.execute(request);

// 异步记录审计日志,不影响主流程响应速度

AuditLog log = new AuditLog();

log.setUserId(request.getUserId());

log.setAction(request.getActionType());

log.setTimestamp(LocalDateTime.now());

auditLogService.logAction(log);

return ResponseEntity.ok(result);

}

}

总结

Spring Boot 中的 @Async 注解提供了强大的异步处理能力,但其默认配置可能不适合高并发生产环境。理解其工作原理和默认行为对于正确使用这一功能至关重要。

关键要点

始终自定义线程池:不要依赖默认配置,特别是无界队列设置

合理设置线程池参数:根据业务类型(CPU/IO密集型)调整核心配置

正确处理异常:实现 AsyncUncaughtExceptionHandler 处理异步异常

使用合适的返回值:优先选择 CompletableFuture 作为返回值类型

监控线程池状态:生产环境中需要监控线程池的运行指标

通过遵循这些最佳实践,您可以充分利用 @Async 的优势,构建出高性能、高可靠的异步处理系统。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐