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();
}