Skip to content

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 + 幂等消费;需要强一致 → 那就不该异步。异步是吞吐优化工具,可靠性边界才是设计决策的核心。

🏗 系统架构师 ​

三个层次按可靠性选:

  1. @Async 加自定义线程池:进程内异步(发通知、记日志、非核心链路)。必须:定制 ThreadPoolTaskExecutor(按业务隔离、有界队列、带日志的拒绝策略)、TaskDecorator 传播 MDC 与安全上下文、异常处理器告警;返回 CompletableFuture 组合编排;
  2. 虚拟线程(3.2+/JDK 21):spring.threads.virtual.enabled=true,阻塞式代码直接获得高并发——IO 密集的简单异步场景优先用它,省掉线程池心智负担;
  3. 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 任务异常(不然静默失败)。