Dubbo之RpcContext原理

1.前言

最近在开发一个消息通知功能,需要将每个功能的dubbo rpc 接口参数通过MQ发送,消费方消费MQ将参数转化成消息通知的必要数据存数据库,用户通过接口获取自己的相关消息.依赖的RPC接口在设计上并没有操作者的参数,需求需要记录操作者.这里有个思路就是利用RpcContext,在一次完整的RPC调用链路中,将需要的参数透传过去.下面讲下使用RpcContext的使用原理以及使用RpcContext所走的坑.

2.上下文信息

RpcContext本质上是一个ThreadLocal,当接收到RPC请求或发起RPC请求时,RpcContext的状态会变化。比如A调用B,B再调用C,则B机器上,在B调用C之前,RpcContext记录的是A调用B的信息,在B调用C之后,RpcContext记录的是B调用C.

3.RpcContext的使用

//服务提供方使用,获取参数
RpcContext.getContext().getAttachments()
//服务器消费方使用,设置参数
RpcContext.getContext().setAttachment() 
//调接口时,必须是A直接到B,如果A没有直接到B,而是先到C,再由C到B,那么在B里getAttachment()获取不到值

4 结合dubbo拦截器使用RpcContext

使用dubbo拦截器的原因是主要有两个:

1) 统一入口设置参数,节省代码方便维护

2) 解决一次完整请求调用涉及多次rpc调用时获取不到上下文中设置的参数值.

在一次线程上下文使用拦截器的例子

public class TraceIdFilter implements Filter {
 
    @Override
    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
        String traceId = RpcContext.getContext().getAttachment("BizId");
        if ( !StringUtils.isEmpty(BizId) ) {
            //从RpcContext里获取bizId并保存
            BizIdUtils.setBizId(bizId);
        } else {
            //交互前重新设置traceId, 避免信息丢失
            RpcContext.getContext().setAttachment("bizId", BizIdUtils.getBizId());
        }
        //实际的rpc调用
        return invoker.invoke(invocation);
    }
}
​
public class BizIdUtils {
 
    private static final ThreadLocal Cache
            = new ThreadLocal();
 
    public static String getBizId() {
        return Cache.get();
    }
 
    public static void setBizId(String bizId) {
        Cache.set(bizId);
    }
 
    public static void clear() {
       Cache.remove();
    }
 
}

如果拦截的方法使用了异步处理,同个线程上下文下可能获取不到值,这时候dubbo拦截器获取值设置进上下文可能是空的,这一点需要注意.

5.RpcContext原理

RpcContext内部有一个ThreadLocal变量,它是作为ThreadLocalMap的key,表明每个线程有一个RpcContext

public class RpcContext {
    private static final ThreadLocal LOCAL = new ThreadLocal() {
        @Override
        protected RpcContext initialValue() {
            return new RpcContext();
        }
    };
​
    //如果get在set之前,则get会返回initialValue()创建的对象
    public static RpcContext getContext() {
        return LOCAL.get();
    }
}

你可能感兴趣的:(dubbo)