在 Spring Boot 中,异步编程(如使用 @Async)是提升应用性能的常用手段。然而,异步线程间的数据传递是一个常见难题。本文将介绍 5 种优雅的实现方式,帮助你解决这一问题!


目录

  1. ThreadLocal + TaskDecorator
  2. TransmittableThreadLocal
  3. DelegatingSecurityContextAsyncTaskExecutor
  4. CompletableFuture 自定义上下文传递
  5. 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) {
// 获取主线程的 ThreadLocal 数据
String mainThreadData = MyThreadLocal.get();
return () -> {
try {
// 将数据设置到子线程中
MyThreadLocal.set(mainThreadData);
runnable.run();
} finally {
// 清理子线程数据
MyThreadLocal.remove();
}
};
}
}
}

// 自定义 ThreadLocal
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 -> {
// 获取主线程的 TransmittableThreadLocal 数据
String mainThreadData = MyTransmittableThreadLocal.get();
return () -> {
try {
// 将数据设置到子线程中
MyTransmittableThreadLocal.set(mainThreadData);
runnable.run();
} finally {
// 清理子线程数据
MyTransmittableThreadLocal.remove();
}
};
});
return executor;
}
}

// 使用 TransmittableThreadLocal
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 通过 TraceIdSpanId 实现分布式追踪,同时支持异步线程间的上下文传递。

代码示例

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() {
// 在异步任务中自动传递 TraceId 和 SpanId
System.out.println("Executing async task with trace context");
}
}

适用场景

  • 分布式系统中的异步任务追踪。
  • 需要集成分布式追踪工具(如 Zipkin)。

总结

方法 优点 缺点 适用场景
ThreadLocal + TaskDecorator 简单易用 不支持复杂线程池 简单异步任务
TransmittableThreadLocal 支持线程池 需要引入第三方库 复杂线程池场景
DelegatingSecurityContextAsyncTaskExecutor 集成 Spring Security 仅支持安全上下文 安全相关任务
CompletableFuture 自定义上下文传递 灵活可控 需要手动管理 手动控制上下文
Spring Cloud Sleuth 集成分布式追踪 依赖 Spring Cloud 生态 分布式系统

选择合适的方式,让你的异步任务更加优雅和高效!🚀