在业务系统中,如果要使用dubbo的隐式传参功能,可以使用RpcContext对象
使用
在服务消费者这一端这样设置即可
RpcContext.getContext().setAttachment("age","22");
然后在服务提供者这一端
String age = RpcContext.getContext().getAttachment("age");
System.out.println("隐式传参获取到的age:" + age);
就可以获取到设置的参数
源码分析
其实要实现隐式传输的传递,也是需要进行一层转换的
隐式传参的原理,用一句话来解释:
在服务发送的时候(也就是服务消费端),会将设置的参数,在发送请求的时候,一起发送出去
在服务提供者这一端,接收到消费端请求的时候,再将参数取出来
AbstractInvoker
@Override
public Result invoke(Invocation inv) throws RpcException {
// if invoker is destroyed due to address refresh from registry, let's allow the current invoke to proceed
if (destroyed.get()) {
logger.warn("Invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " is destroyed, "
+ ", dubbo version is " + Version.getVersion() + ", this invoker should not be used any longer");
}
RpcInvocation invocation = (RpcInvocation) inv;
invocation.setInvoker(this);
if (attachment != null && attachment.size() > 0) {
invocation.addAttachmentsIfAbsent(attachment);
}
// 获取rpcContext中的参数,将隐式传递的参数,放到invocation对象中
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
invocation.addAttachments(contextAttachments);
}
if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
}
}
invoke方法,会在服务消费者发起调用的时候,被调用到,上面的代码中,我只截取了一部分源码
可以看到,其中一段代码,就是将rpcContext中的隐式参数,取出来,放在invocation对象中,所以,这里就是服务调用者,将RpcContext转换的地方
ContextFilter
这个filter,就是服务提供者,解析invocation中隐式参数的代码
Map<String, String> attachments = invocation.getAttachments();
if (attachments != null) {
if (RpcContext.getContext().getAttachments() != null) {
RpcContext.getContext().getAttachments().putAll(attachments);
} else {
RpcContext.getContext().setAttachments(attachments);
}
}
这里我也是只截取了一部分代码,可以看到,先从invocation对象中获取到所有的参数,然后放到了服务提供者这一段的RpcContext对象中
那为什么这个filter,会在服务提供者执行的时候,被调用呢?
@Activate(group = Constants.PROVIDER, order = -10000)
因为这个注解,就表示了只在provider这一侧生效
总结
对于隐式传参来说,并不是直接把RpcContext对象传递过去,而是中间进行了一层转换
RpcContext(消费者) --> Invocation --> RpcContext(服务端)