Dubbo学习之路(十三):RpcContext隐式传参

RpcContext:试一次请求的零时的上下文记录器,内部的实现是一个 ThreadLocal,我们看一下内部实现

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

在之前的Filter文章中,其实有提到过这个,在ConsumerContextFilter中,我们会创建RpcContext并且初始化一些数据,然后在后续的业务中我们可以给RpcContext里面添加attachments属性,进行属性的传递,在ContextFilter中接收设置的attachments属性值。

我们看一下ConsumerContextFilter:初始化了RpcContext并且设置了一些参数的值

RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());

这个时候我们在业务里面就可以设置一些属性值,进行隐式传参

RpcContext.getContext().setAttachment("name", "小明");
RpcContext.getContext().setAttachment("sex", "男");

然后在调用provider时,会经过ContextFilter,在这里我们就可以获取到consumer传过来的参数,然后依然是设置到自己的RpcContext,在后续业务中使用

Map attachments = invocation.getAttachments();
RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());

        // mreged from dubbox
        // we may already added some attachments into RpcContext before this filter (e.g. in rest protocol)
        if (attachments != null) {
            if (RpcContext.getContext().getAttachments() != null) {
                RpcContext.getContext().getAttachments().putAll(attachments);
            } else {
                RpcContext.getContext().setAttachments(attachments);
            }
        }

这里我们为什么会在invocation中拿到数据呢?我们看一下在调用DubboInvoker的时候,其实是走的抽象类AbstractInvoker中的invoke方法,这里会拿到之前设置的RpcContext的Attachments的值,设置到invocation的attachments属性中。

if (attachment != null && attachment.size() > 0) {
            invocation.addAttachmentsIfAbsent(attachment);
        }
        Map context = RpcContext.getContext().getAttachments();
        if (context != null) {
            invocation.addAttachmentsIfAbsent(context);
        }

而且这里是可以实现异步调用的

if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
            invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
        }

这里通过获取async参数,如果配置了这个参数,我们会设置invocation中为异步

然后在DubboInvoker中,判断是不是异步,如果是异步设置setFuture,然后直接相应,后续通过RpcContext获取值。

boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
else if (isAsync) {
                ResponseFuture future = currentClient.request(inv, timeout);
                RpcContext.getContext().setFuture(new FutureAdapter(future));
                return new RpcResult();
            } 
  

 

你可能感兴趣的:(Dubbo,Dubbo)