Spring Boot 中如何实现异步处理?
- 标签:Spring Boot、后端、Spring
🏛 业务架构师
Spring Boot 中实现异步处理,按可靠性要求分层选型:
1. @Async 注解(进程内异步,最轻):
java
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("bizExecutor")
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(8); ex.setMaxPoolSize(16);
ex.setQueueCapacity(500);
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 背压
return ex;
}
}
@Async("bizExecutor")
public void sendNotification(Long orderId) { ... }注意:同类自调用失效(代理机制)、默认线程池要替换、异常与 ThreadLocal 上下文要治理。
2. CompletableFuture + 自定义线程池:需要编排(并行调三个下游再聚合)时用,allOf 汇聚把串行 RT 叠加变成最长者;JDK 21+ 虚拟线程让这类编排的成本进一步下降。
3. MQ(跨进程、可靠异步,业务主流):@Async 的任务是"进程内、可丢",发券、扣积分、通知这类不能丢的业务动作必须走 MQ——落库 + 重试 + 死信,重启不丢任务。
架构师视角的决策框架就一条:先问"这个任务丢了会怎样"。丢了无感(日志、埋点)→ @Async;丢了可补偿 → MQ + 幂等消费;需要强一致 → 那就不该异步。异步是吞吐优化工具,可靠性边界才是设计决策的核心。
🏗 系统架构师
三个层次按可靠性选:
@Async加自定义线程池:进程内异步(发通知、记日志、非核心链路)。必须:定制 ThreadPoolTaskExecutor(按业务隔离、有界队列、带日志的拒绝策略)、TaskDecorator 传播 MDC 与安全上下文、异常处理器告警;返回CompletableFuture组合编排;- 虚拟线程(3.2+/JDK 21):
spring.threads.virtual.enabled=true,阻塞式代码直接获得高并发——IO 密集的简单异步场景优先用它,省掉线程池心智负担; - MQ(RocketMQ/Kafka):跨服务、需要可靠投递的异步(订单到物流、积分)——持久化、重试、削峰,天然水平扩展。
决策口诀:崩溃可丢的用进程内异步;崩溃不可丢的走 MQ 加本地消息表;追求吞吐的 IO 并发用虚拟线程。
架构提醒:异步的本质是隔离故障域加削峰,不是「更快返回」。异步化后必须配套 traceId 贯穿线程与队列、对账兜底——否则故障排查成本指数级上升,异步越用越多、问题越来越难查。
💻 全栈开发专家
按场景分层选:
1. @Async 方法级异步(最常用):
java
@EnableAsync
@Configuration
public class AsyncConfig {
@Bean("mailExecutor")
public ThreadPoolTaskExecutor mailExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(4);
ex.setMaxPoolSize(8);
ex.setQueueCapacity(200);
ex.setThreadNamePrefix("mail-");
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
ex.setTaskDecorator(new MdcTaskDecorator()); // 传 traceId,链路不断
return ex;
}
}
@Service
public class MailService {
@Async("mailExecutor") // 指定池,别用默认
public void send(OrderEvent e) { ... }
}2. CompletableFuture 编排:并行调多个下游再聚合(allOf),配自定义池。
3. 虚拟线程(Boot 3.2+):spring.threads.virtual.enabled=true,高并发 IO 直接同步写法,不手写池。
4. MQ 解耦削峰:跨服务、需要可靠投递(重试、持久化)就上 RocketMQ/Kafka。
选型递进:请求内异步 @Async → 并行编排 CF → 虚拟线程扛并发 → MQ 扛峰值与解耦。排查三件套:线程名日志(确认真异步了)、线程池指标(活跃/队列/拒绝数接 Micrometer)、AsyncUncaughtExceptionHandler 收集 void 任务异常(不然静默失败)。