(十五)RpcContext对象

来源:互联网 发布:淘宝大马士革刀真假 编辑:程序博客网 时间:2024/06/05 05:19
比如现在消费者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)方法,就会发送参数给提供者。
阅读全文
0 0