在 Spring Boot 中,异步编程(如使用 @Async
)是提升应用性能的常用手段。然而,异步线程间的数据传递是一个常见难题。本文将介绍 5 种优雅的实现方式,帮助你解决这一问题!
目录
- ThreadLocal + TaskDecorator
- TransmittableThreadLocal
- DelegatingSecurityContextAsyncTaskExecutor
- CompletableFuture 自定义上下文传递
- Spring Cloud Sleuth 分布式追踪
1. ThreadLocal + TaskDecorator
实现原理
- 通过
TaskDecorator
在任务执行前将主线程的 ThreadLocal
数据复制到子线程中。
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskDecorator; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration public class AsyncConfig {
@Bean public ThreadPoolTaskExecutor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setTaskDecorator(new ContextCopyingDecorator()); return executor; }
static class ContextCopyingDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { String mainThreadData = MyThreadLocal.get(); return () -> { try { MyThreadLocal.set(mainThreadData); runnable.run(); } finally { MyThreadLocal.remove(); } }; } } }
class MyThreadLocal { private static final ThreadLocal<String> context = new ThreadLocal<>();
public static void set(String value) { context.set(value); }
public static String get() { return context.get(); }
public static void remove() { context.remove(); } }
|
适用场景
- 需要在异步任务中传递少量数据。
- 数据生命周期较短。
2. TransmittableThreadLocal
实现原理
TransmittableThreadLocal
是阿里开源的线程本地变量工具,支持线程池场景下的数据传递。
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import com.alibaba.ttl.TransmittableThreadLocal; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration public class AsyncConfig {
@Bean public ThreadPoolTaskExecutor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setTaskDecorator(runnable -> { String mainThreadData = MyTransmittableThreadLocal.get(); return () -> { try { MyTransmittableThreadLocal.set(mainThreadData); runnable.run(); } finally { MyTransmittableThreadLocal.remove(); } }; }); return executor; } }
class MyTransmittableThreadLocal { private static final TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
public static void set(String value) { context.set(value); }
public static String get() { return context.get(); }
public static void remove() { context.remove(); } }
|
适用场景
3. DelegatingSecurityContextAsyncTaskExecutor
实现原理
- Spring Security 提供的
DelegatingSecurityContextAsyncTaskExecutor
可以传递安全上下文(SecurityContext)。
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor;
@Configuration public class AsyncConfig {
@Bean public ThreadPoolTaskExecutor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); return executor; }
@Bean public DelegatingSecurityContextAsyncTaskExecutor securityContextAsyncExecutor(ThreadPoolTaskExecutor executor) { return new DelegatingSecurityContextAsyncTaskExecutor(executor); } }
|
适用场景
- 需要传递安全上下文(如用户认证信息)。
- 与 Spring Security 集成。
4. CompletableFuture 自定义上下文传递
实现原理
- 通过
CompletableFuture
的钩子方法(如 thenApply
)手动传递上下文。
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import java.util.concurrent.CompletableFuture;
public class AsyncService {
public CompletableFuture<String> asyncTask() { String mainThreadData = MyThreadLocal.get();
return CompletableFuture.supplyAsync(() -> { try { MyThreadLocal.set(mainThreadData); return "Task completed with data: " + MyThreadLocal.get(); } finally { MyThreadLocal.remove(); } }); } }
|
适用场景
- 使用
CompletableFuture
实现异步编程。
- 需要手动控制上下文传递。
5. Spring Cloud Sleuth 分布式追踪
实现原理
- Spring Cloud Sleuth 通过
TraceId
和 SpanId
实现分布式追踪,同时支持异步线程间的上下文传递。
代码示例
1 2 3 4 5 6
| # application.yml spring: sleuth: enabled: true async: enabled: true
|
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service;
@Service public class AsyncService {
@Async public void asyncTask() { System.out.println("Executing async task with trace context"); } }
|
适用场景
- 分布式系统中的异步任务追踪。
- 需要集成分布式追踪工具(如 Zipkin)。
总结
方法 |
优点 |
缺点 |
适用场景 |
ThreadLocal + TaskDecorator |
简单易用 |
不支持复杂线程池 |
简单异步任务 |
TransmittableThreadLocal |
支持线程池 |
需要引入第三方库 |
复杂线程池场景 |
DelegatingSecurityContextAsyncTaskExecutor |
集成 Spring Security |
仅支持安全上下文 |
安全相关任务 |
CompletableFuture 自定义上下文传递 |
灵活可控 |
需要手动管理 |
手动控制上下文 |
Spring Cloud Sleuth |
集成分布式追踪 |
依赖 Spring Cloud 生态 |
分布式系统 |
选择合适的方式,让你的异步任务更加优雅和高效!🚀