Dubbo學習之路(十三):RpcContext隱式傳參

RpcContext:試一次請求的零時的上下文記錄器,內部的實現是一個 ThreadLocal,我們看一下內部實現

private static final ThreadLocal<RpcContext> LOCAL = new ThreadLocal<RpcContext>() {
        @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<String, String> 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<String, String> 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<Object>(future));
                return new RpcResult();
            }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章