2-3 隐式传参

应用

先看下dubbo的隐式传参是个什么效果。代码如下所示。

public class PersonServiceImpl implements PersonService {
    public String say(String name) {
        Object obj = RpcContext.getContext().getAttachments();
        System.out.println("获取隐式传参的信息"+obj);
        return name + " say hello ";
    }
}

public class MainClient {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonService p= applicationContext.getBean(PersonService.class);
        RpcContext.getContext().setAttachment("aaa", "bbb");
        RpcContext.getContext().setAttachment("eee", "ccc");
        System.out.println(p.say("abcd"));
    }
}

上面的代码是服务消费方打印的隐式参数。后面的代码是客户端传递的隐式参数。

服务提供者:

根据之前讲的,我们知道dubbo的服务提供者接受到netty请求,会把参数封装成一个com.alibaba.dubbo.remoting.exchange.Request对象。 该对象有一个属性是Object mData。实际调用的时候,可能会是DecodeableRpcInvocation,该类继承自RpcInvocation。在RpcInvocation中有两个属性。Object[] arguments和Map attachments这里的arguments就是函数参数,而attachments就是隐式参数。

Request是请求信息,里面有一个属性是Invocation,同时Invocation的属性也有Request,两者是相互持有的关系。

在dubbo内部函数调用链路中,都是用Invocation在作为函数参数传递。到如下代码的时候,会封装这些隐式参数。

public class ContextFilter implements Filter {
    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
        Map attachments = invocation.getAttachments();
        if (attachments != null) {
            attachments = new HashMap(attachments);
            attachments.remove(Constants.PATH_KEY);
            attachments.remove(Constants.GROUP_KEY);
            attachments.remove(Constants.VERSION_KEY);
            attachments.remove(Constants.DUBBO_VERSION_KEY);
            attachments.remove(Constants.TOKEN_KEY);
            attachments.remove(Constants.TIMEOUT_KEY);
        }
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                //设置隐式参数。
                .setAttachments(attachments)
                .setLocalAddress(invoker.getUrl().getHost(), 
                                 invoker.getUrl().getPort());
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation)invocation).setInvoker(invoker);
        }
        try {
           //调用前绑定到RpcContext中,调用后在finally去除掉。
            return invoker.invoke(invocation);
        } finally {
            RpcContext.removeContext();
        }
    }
}

而实际上是跟着线程绑定的。

public class RpcContext {
    private static final ThreadLocal LOCAL = new ThreadLocal() {
        @Override
        protected RpcContext initialValue() {
            return new RpcContext();
        }
    };
    public static RpcContext getContext() {
        return LOCAL.get();
    }

服务消费者:

消费者和生产者的代码原理是一样的,消费者代码如下:

@Activate(group = Constants.CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {
    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(), 
                                  invoker.getUrl().getPort());
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation)invocation).setInvoker(invoker);
        }
        try {
            return invoker.invoke(invocation);
        } finally {
            RpcContext.getContext().clearAttachments();
        }
    }
}

你可能感兴趣的:(2-3 隐式传参)