在不修改方法签名与参数定义的情况下,可以通过 RpcContext 上的 setAttachment 和 getAttachment 在服务消费方和提供方之间进行参数的隐式传递。
隐式参数传递支持以下两个方向:
- 从消费方到提供方,也就是在请求发起时,在方法参数之外通过 attachment 传递附加参数。
- 从提供方到消费方,也就是在响应结果返回时,在响应结果之外通过 attachment 传递附加参数。
理解隐式参数传递的最直接方式 http header,它的工作方式与 http header 完全一致,在 GET 或 POST 请求体之外可以传递任意多个 header 参数。
在实现原理上,对于不同的协议,attachment 的实现方式略有不同:
- 对于 triple 协议,attachment 会转换为标准的 http header 进行传输。
- 对于 dubbo 协议,attachment 是编码在协议体的固定位置进行传输,具体请参见 dubbo 协议规范。
注意
- 在使用 triple 协议时,由于 http header 的限制,仅支持小写的 ascii 字符
- path, group, version, dubbo, token, timeout 一些 key 是保留字段,传递 attachment 时应避免使用,尽量通过业务前缀等确保 key 的唯一性。
RpcContext 被拆分为四大模块(ServerContext、ClientAttachment、ServerAttachment 和 ServiceContext)。
- ServiceContext:在 Dubbo 内部使用,用于传递调用链路上的参数信息,如 invoker 对象等
- ClientAttachment:在 Client 端使用,往 ClientAttachment 中写入的参数将被传递到 Server 端
- ServerAttachment:在 Server 端使用,从 ServerAttachment 中读取的参数是从 Client 中传递过来的
- ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到
客户端
@Component
public class RpcContextTask implements CommandLineRunner {@DubboReferenceprivate GreetingsService greetingsService;@Overridepublic void run(String... args) throws Exception {// 客户端写RpcContext.getClientAttachment().setAttachment("k1", "v1");String k1 = greetingsService.sayHello("k1");System.out.println("K1----->>>" +k1);// 读取服务端写入的数据String k2 = RpcContext.getServerContext().getAttachment("k2");System.out.println("K2----->>>:" + k2);}
}
服务端
@DubboService
public class RpcContextGreetingsServiceImpl implements GreetingsService {@Overridepublic String sayHello(String name) {// 读取客户端写入的数据String k1 = RpcContext.getServerAttachment().getAttachment("k1");System.out.println("k1:" + k1);// 服务端写RpcContext.getServerContext().setAttachment("k2", "v2");return "hello " + name;}
}