(十五)RpcContext物件
阿新 • • 發佈:2019-02-02
比如現在消費者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:
可以給個star,^0^.