2-3 隐式传参
2018-12-30 本文已影响0人
xhrg
应用
先看下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<String, String> attachments这里的arguments就是函数参数,而attachments就是隐式参数。
Request是请求信息,里面有一个属性是Invocation,同时Invocation的属性也有Request,两者是相互持有的关系。
在dubbo内部函数调用链路中,都是用Invocation在作为函数参数传递。到如下代码的时候,会封装这些隐式参数。
public class ContextFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Map<String, String> attachments = invocation.getAttachments();
if (attachments != null) {
attachments = new HashMap<String, String>(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<RpcContext> LOCAL = new ThreadLocal<RpcContext>() {
@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();
}
}
}