Dubbo RPCContext用手动清除吗?
Dubbo RPCContext用手动清除吗?
月伴飞鱼Dubbo 在以下情况下会自动清理 RpcContext
:
同步 RPC 调用结束后:
RpcContext.getContext()
的数据会被当前线程回收,但如果是线程池模式,数据可能被污染。服务端调用完成后:
- 当 Dubbo 服务端 处理完请求后,会清理
RpcContext
,防止数据泄漏到下一个请求。消费者(Consumer)发起 RPC 调用时:
RpcContext
不会跨请求复用,下次新的RpcContext.getContext()
仍然是新的实例。
✅ 示例(同步调用,Dubbo 自动清理)
1 | public void testRpcContext() { |
结果:
traceId
在 RPC 调用后被清空,Dubbo 自动清理。
Dubbo 什么时候不会自动清理 RpcContext
?
虽然 Dubbo 在请求完成后会清理
RpcContext
,但某些情况下RpcContext
可能不会被正确清除,需要手动清理。
❌ 1. Dubbo 异步调用
Dubbo 异步调用不会自动清理
RpcContext
。因为线程池可能会复用
ThreadLocal
的数据,导致下一个请求仍然携带上一个请求的RpcContext
数据。
1 | public void asyncCall() { |
🔴 如果不手动清理,异步线程可能复用上一个请求的 RpcContext
数据!
❌ 2. 使用线程池(如 ExecutorService
)
如果你的应用使用线程池(如
ExecutorService
)处理 Dubbo 请求,线程池不会自动清理RpcContext
,导致数据污染。
1 | ExecutorService executorService = Executors.newFixedThreadPool(5); |
🔴 如果线程池中的线程未手动清理 RpcContext
,后续任务可能复用 traceId
,导致数据污染。
✅ 解决方案
在任务结束时手动
clearAttachments()
:1
2
3
4
5
6try {
RpcContext.getContext().setAttachment("traceId", "abc123");
demoService.sayHello("Dubbo");
} finally {
RpcContext.getContext().clearAttachments();
}使用 Dubbo
InheritableThreadLocal
(适用于 Dubbo 3.x)1
RpcContext.removeContext(true);
❌ 3. 在 Filter 或拦截器中传递 RpcContext
如果你在 Dubbo
Filter
里存放了RpcContext
的数据,可能不会自动清理,影响后续请求。
1 | public class CustomFilter implements Filter { |
✅ 确保在 finally
里清理 RpcContext
,防止数据污染。
解决方案:如何正确清理 RpcContext
?
✅ 手动 clearAttachments()
无论 Dubbo 是否会自动清理,养成手动清理的习惯,避免数据污染。
1 | try { |
✅ 使用 RpcContext.removeContext(true)
(Dubbo 3.x 推荐)
Dubbo 3.x 提供了
removeContext(true)
,可以完全清理当前线程RpcContext
。
1 | RpcContext.removeContext(true); |
✅ 适用于:
- 线程池中使用
RpcContext
- Dubbo 异步调用
- 需要彻底清理
RpcContext
✅ 在 AOP 或 Filter 中全局清理
如果你的应用里
RpcContext
传递较多,可以在 AOP 或 DubboFilter
里统一清理,减少手动调用clearAttachments()
的麻烦。
方式 1:Spring AOP 自动清理
1 |
|
优点:拦截所有 Dubbo 方法调用后自动清理
RpcContext
。
方式 2:在 Dubbo Filter
里自动清理
1 | public class RpcContextCleanFilter implements Filter { |
然后在 dubbo.xml
或 dubbo.properties
里配置:
1 | <dubbo:provider filter="rpcContextCleanFilter"/> |
优点:全局自动清理 RpcContext
,防止数据泄漏。
结论
情况 | Dubbo 是否自动清理? | 推荐解决方案 |
---|---|---|
同步 RPC 调用 | ✅ 是 | 默认安全,但建议 finally 里清理 |
异步调用(CompletableFuture) | ❌ 否 | 手动 clearAttachments() |
线程池复用(ExecutorService) | ❌ 否 | finally 里清理 RpcContext |
Dubbo Filter 或 AOP |
❌ 否 | 拦截器里清理 RpcContext |
Dubbo 3.x 版本 | ❌ 否 | RpcContext.removeContext(true) |
最佳实践
- 同步调用,建议
try-finally
里clearAttachments()
。 - 异步调用,必须
clearAttachments()
,避免线程池数据污染。 - 线程池调用 Dubbo,使用
RpcContext.removeContext(true)
清理ThreadLocal
。 - 全局清理可以用 Dubbo
Filter
或 Spring AOP 自动处理。
结论
Dubbo 默认会在请求完成后清理
RpcContext
,但异步调用和线程池不会自动清理。所以要手动清理,或者在拦截器里全局清理,避免数据污染。