(十五)RpcContext对象

本文详细解析了Dubbo框架中RPC调用时如何通过RpcContext传递附加参数,并介绍了参数是如何从消费者传递到提供者的具体流程。

比如现在消费者A调用提供者B,
在RPC调用之前,消费者可以调用RpcContext.getContext().setAttachment(key, value);
设置一些隐含参数,然后在提供者B可以通过RpcContext.getContext().getAttachment(key);拿到key的value。
如果B又接着调用C,那么RpcContext则会放着B的调用C的参数,而之前A调用B的参数已经是不存在的。
直接看下RpcContext的源码。

public class RpcContext {
    
    private static final ThreadLocal<RpcContext> LOCAL = new ThreadLocal<RpcContext>() {
        @Override
        protected RpcContext initialValue() {
            return new RpcContext();
        }
    };

    /**
     * get context.
     *
     * @return context
     */
    public static RpcContext getContext() {
        return LOCAL.get();
    }

    //省略其他属性
    private Future<?> future;

    private final Map<String, String> attachments = new HashMap<String, String>();

        /**
     * get attachment.
     *
     * @param key
     * @return attachment
     */
    public String getAttachment(String key) {
        return attachments.get(key);
    }

    /**
     * set attachment.
     *
     * @param key
     * @param value
     * @return context
     */
    public RpcContext setAttachment(String key, String value) {
        if (value == null) {
            attachments.remove(key);
        } else {
            attachments.put(key, value);
        }
        return this;
    }

 


看出来RpcContext对象是绑定在线程临时变量LOCAL上,所以可以通过线程临时变量来获取到RpcContext的相关参数值。
下面看看RPC调用时是怎么将RpcContext上的参数传输给提供者的,类com.alibaba.dubbo.rpc.protocol.AbstractInvoker<T>的一段源码:

 

 

public Result invoke(Invocation inv) throws RpcException {
    if(destroyed) {
        throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost()
                                        + " use dubbo version " + Version.getVersion()
                                        + " is DESTROYED, can not be invoked any more!");
    }
    RpcInvocation invocation = (RpcInvocation) inv;
    invocation.setInvoker(this);
    if (attachment != null && attachment.size() > 0) {
        invocation.addAttachmentsIfAbsent(attachment);
    }
    Map<String, String> context = RpcContext.getContext().getAttachments(); //41处
    if (context != null) {
        invocation.addAttachmentsIfAbsent(context);
    }
    if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)){
        invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
    }
    RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
    
    
    try {
        return doInvoke(invocation);
    } catch (InvocationTargetException e) { // biz exception
        Throwable te = e.getTargetException();
        if (te == null) {
            return new RpcResult(e);
        } else {
            if (te instanceof RpcException) {
                ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
            }
            return new RpcResult(te);
        }
    } catch (RpcException e) {
        if (e.isBiz()) {
            return new RpcResult(e);
        } else {
            throw e;
        }
    } catch (Throwable e) {
        return new RpcResult(e);
    }
}

protected abstract Result doInvoke(Invocation invocation) throws Throwable;


在调用提供者之前,在源码“41处”,会获取当前线程临时变量里的RpcContext对象,再将RpcContext对象里的参数设置到Invocation对象,最后调用doInvoke(Invocation invocation)方法,就会发送参数给提供者。

自己写了个RPC:

https://github.com/nytta

可以给个star,^0^.

### RPCContext in Distributed Systems or Microservices Architecture In distributed systems and microservices architectures, `RPCContext` plays an essential role by encapsulating information necessary for Remote Procedure Calls (RPC). This context typically includes metadata about the caller, security credentials, transaction identifiers, and other contextual data required to process requests across service boundaries[^1]. The design patterns used when transitioning from monolithic applications to microservices often involve creating well-defined interfaces through which services communicate. In this setup, each microservice operates independently but interacts with others via lightweight protocols like gRPC or REST APIs. The `RPCContext` ensures that all relevant environmental details are passed along during these interactions so that downstream services can make informed decisions based on complete information. For instance, within a multi-runtime microservices architecture described elsewhere[^2], maintaining consistent behavior across different runtimes requires careful management of such contexts. Services must propagate headers containing trace IDs, user authentication tokens, etc., ensuring end-to-end visibility into operations spanning multiple nodes. When implementing solutions involving PyTorch's distributed training capabilities using torch.nn.distributed packages, developers might encounter issues related to how processes synchronize their states over networks. While not directly tied to traditional RPC mechanisms, similar principles apply regarding session establishment and message passing between peers participating in parallel computations[^3]. Ensuring proper initialization of communication channels and handling potential failures gracefully becomes critical here as well. Regarding PacificA’s interaction model where changes in topology trigger updates rather than every routine request hitting the configuration manager[^4], managing state consistency efficiently while minimizing overhead remains key. Here too, concepts analogous to those found in setting up reliable RPC frameworks come into play—such as versioning schemes, fallback strategies upon detecting misconfigurations, and optimizing performance under varying network conditions. ```python import grpc from my_service_pb2 import MyRequest, MyResponse from my_service_pb2_grpc import MyServiceStub def call_rpc_with_context(context_data): channel = grpc.insecure_channel('localhost:50051') stub = MyServiceStub(channel) # Attach custom metadata to the outgoing RPC call. metadata = [ ('trace-id', 'abc123'), ('user-token', 'xyz789'), *context_data.items() ] response = stub.MyMethod(MyRequest(), metadata=metadata) return response.value ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值