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