SOFA 源码分析 — 链路数据透传
前言
SOFA—RPC 支持数据链路透传功能,官方解释:
链路数据透传功能支持应用向调用上下文中存放数据,达到整个链路上的应用都可以操作该数据。 使用方式如下,可分别向链路的 request 和 response 中放入数据进行透传,并可获取到链路中相应的数据。
使用方式:
RpcInvokeContext.getContext().putRequestBaggage("key_request","value_request");
RpcInvokeContext.getContext().putResponseBaggage("key_response","value_response");
RpcInvokeContext.getContext().getAllRequestBaggage("key_request");
RpcInvokeContext.getContext().getAllRequestBaggage("key_response");
源码分析
从这个 4 句代码开始看。
关键类: RpcInvokeContext,该类是一个 基于ThreadLocal的面向业务开发者使用的上下文传递对象
。
内部维护了一个 ThreadLocal 对象。
protected static final ThreadLocal<RpcInvokeContext> LOCAL = new ThreadLocal<RpcInvokeContext>();
value 是一个 RpcInvokeContext 对象。
当调用 getContext 的时候,就会从当前线程获取 RpcInvokeContext 对象。
该类定义了以下属性:
- boolean BAGGAGE_ENABLE 是否开启上下文透传功能,关闭后,会提高性能
- Integer timeout 用户自定义超时时间,单次调用生效
- String targetURL 用户自定义对方地址,单次调用生效
- String targetGroup 用户自定义对方分组
- SofaResponseCallback responseCallback 用户自定义Callback,单次调用生效
- ResponseFuture<?> future
- ConcurrentMap<String, Object> map 自定义属性
- Map<String, String> requestBaggag 请求上的透传数据
- Map<String, String> responseBaggage 响应上的透传数据
知道了基本的数据结构,再看看上面的几个方法:
- putRequestBaggage()
- putResponseBaggage()
- getAllRequestBaggage()
- getAllRequestBaggage()
其实都是从 Map 中获取数据,不过,貌似官方的例子有点问题,后面两个例子不对。没有 key 。待我提个 issue。
总结
这个功能让我想到了我在公司项目中使用的 CurrentUser 功能,也是使用的 ThreadLocal,将用户的信息存在线程中,这样就不必将常用数据在方法参数中传递了,省了很多事。只不过异步的时候,可能会有点问题,需要手动将 ThreadLocal 传递到异步线程中。
不过,我没有使用手动传递,我是这么设计的:自定义线程池和线程工厂,线程工厂创建线程的时候,会将主线程的 ThreadLocal 复制到异步线程中,并自定义了线程类,在 finally 块中删除 ThreadLocal,非常完美的一个设计。这样就不必每次手动传递并手动删除了。
好了,这个功能还是很简单的。但非常实用,不过要是能加上我上面设计的那个功能就好啦! 哈哈!