阅读 143

Dubbo隐式参数

简介

在dubbo应用互相调用过程中,某些dubbo方法可能需要一些非业务属性的参数,例如traceId、userInfo、token等,如果在方法签名上增加这些参数,那么代码看上去会有些不优雅。那么有没有更好的方法呢?

Dubbo框架通过RpcContext#attachments提供了隐式参数传递的功能。

服务消费方可以通过RpcContext.getContext().setAttachment()方法设置附加属性键值对,服务提供方可以通过RpcContext.getContext().getAttachment()在服务方法内获取设置的附加属性键值对。通常用于框架集成、不建议用于传递常规业务参数(影响代码可读性等原因)。

用法示例

在服务消费方端设置隐式参数

@Test
public void test() {
    // 隐式传参,会隐式将这些参数发送到服务器端
    RpcContext.getContext().setAttachment("userId", "1");
    RpcContext.getContext().setAttachment("traceId", "Hemx4j");

    String result = xxxService.sayHello("隐式参数");
    System.out.println("result = " + result);
}复制代码

在服务提供方端获取隐式参数

@Override
public String sayHello(String name) {
    // 获取服务消费方传入的隐式参数
    Map<String, String> attachments = RpcContext.getContext().getAttachments();
    System.out.println("attachments = " + attachments);

    String userId = RpcContext.getContext().getAttachment("userId");
    String traceId = (String) RpcContext.getContext().getAttachment("traceId");
    System.out.println("userId = " + userId);
    System.out.println("traceId = " + traceId);

    return "Hello, " + name;
}复制代码

源码解析

服务消费方绑定并传递隐式参数

在服务消费方,发起远程调用时,会从RpcContext获取到附加属性键值对,然后放入到RpcInvocation#attachments中,最后经过网络传递到服务提供端。

org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke

org.apache.dubbo.rpc.RpcInvocation#addAttachments

@Override
public Result invoke(final Invocation invocation) throws RpcException {
    checkWhetherDestroyed();

    // binding attachments into invocation.
    Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
    if (contextAttachments != null && contextAttachments.size() != 0) {
        ((RpcInvocation) invocation).addAttachments(contextAttachments);
    }

    ...
    return doInvoke(invocation, invokers, loadbalance);
}

public void addAttachments(Map<String, String> attachments) {
    if (attachments == null) {
        return;
    }
    if (this.attachments == null) {
        this.attachments = new HashMap<String, String>();
    }
    this.attachments.putAll(attachments);
}复制代码

服务提供方获取并回收隐式参数

在服务提供方,接受到远程请求时,会通过ContextFilter对请求进行拦截,然后从RpcInvocation#attachments获取到附加属性键值对,并将键值对设置到RpcContext中。后续提供方如果需要使用到attachments值,只需要从RpcContext获取即可。

org.apache.dubbo.rpc.filter.ContextFilter#invoke

@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    
    // 从Invocation获取附加属性键值对attachments
    Map<String, String> attachments = invocation.getAttachments();

    ...
        
    // 将键值对设置到RpcContext中
    if (attachments != null) {
        if (RpcContext.getContext().getAttachments() != null) {
            RpcContext.getContext().getAttachments().putAll(attachments);
        } else {
            RpcContext.getContext().setAttachments(attachments);
        }
    }

    ...
        
    try {
        return invoker.invoke(invocation);
    } finally {
        // 清空当前线程的RpcContext对象,隐式参数不会继续传递给下一个应用
        RpcContext.removeContext();
        RpcContext.removeServerContext();
    }
}


作者:逍遥道长
链接:https://juejin.cn/post/7022261378102591495


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐