Dubbo-协议和序列化
Dubbo rpc调用远程方法就像调用本地方法一样!!方便的背后,肯定有很多技术的支持。
本文通过hello world简单跟踪一下源码,简单体验一下dubbo背后的技术。
1. hello world中远程调用源码分析
- 入口
String hello = providerService.sayHello(next);
2.debug时F7进入com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler
package com.alibaba.dubbo.rpc.proxy;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcInvocation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//继承了InvocationHandler——》动态代理
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker; //jdk动态代理接口,这个Invoker就是接口
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName(); //被代理方法名
Class<?>[] parameterTypes = method.getParameterTypes(); //方法参数列表
//如果代理的是Object对象
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this.invoker, args);
//如果代理方法是toString或hashCode或equals
} else if ("toString".equals(methodName) && parameterTypes.length == 0) {
return this.invoker.toString();
} else if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return this.invoker.hashCode();
} else {
return "equals".equals(methodName) && parameterTypes.length == 1 ? this.invoker.equals(args[0]) : this.invoker.invoke(new RpcInvocation(method, args)).recreate(); //在这里继续F7
}
}
}
//被代理接口
public interface Invoker<T> extends Node {
Class<T> getInterface();
Result invoke(Invocation var1) throws RpcException;
}
//Result
package com.alibaba.dubbo.rpc;
import java.util.Map;
public interface Result {
Object getValue();
Throwable getException();
boolean hasException();
Object recreate() throws Throwable;
/** @deprecated */
@Deprecated
Object getResult();
Map<String, String> getAttachments();
String getAttachment(String var1);
String getAttachment(String var1, String var2);
}
//Invocation
package com.alibaba.dubbo.rpc;
import java.util.Map;
public interface Invocation {
String getMethodName();
Class<?>[] getParameterTypes();
Object[] getArguments();
Map<String, String> getAttachments();
String getAttachment(String var1);
String getAttachment(String var1, String var2);
Invoker<?> getInvoker();
}
//RpcInvocation
public class RpcInvocation implements Invocation, Serializable {...}
- 继续F7进入com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
.
.
.
//该类中又有一个invoker
private final Invoker<T> invoker;
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
String value = this.directory.getUrl().getMethodParameter(invocation.getMethodName(), "mock", Boolean.FALSE.toString()).trim();
//这一大坨先不管
if (value.length() != 0 && !value.equalsIgnoreCase("false")) {
if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + this.directory.getUrl());
}
result = this.doMockInvoke(invocation, (RpcException)null);
} else {
try {
result = this.invoker.invoke(invocation);
} catch (RpcException var5) {
if (var5.isBiz()) {
throw var5;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + this.directory.getUrl(), var5);
}
result = this.doMockInvoke(invocation, var5);
}
}
//调试时,进入这个,又是另一个Invoker
} else {
result = this.invoker.invoke(invocation);
}
return result;
}
.
.
.
- 另一个Invoker, com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker
public Result invoke(Invocation invocation) throws RpcException {
this.checkWhetherDestroyed();
LoadBalance loadbalance = null;
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
//这个先不管,没进入
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation)invocation).addAttachments(contextAttachments);
}
List<Invoker<T>> invokers = this.list(invocation);
//这里应该是选择负载均衡策略,进入了...
if (invokers != null && !invokers.isEmpty()) {
loadbalance = (LoadBalance)ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(((Invoker)invokers.get(0)).getUrl().getMethodParameter(RpcUtils.getMethodName(invocation), "loadbalance", "random"));
}
RpcUtils.attachInvocationIdIfAsync(this.getUrl(), invocation);
//进入这个,前面不懂,先不要在意
return this.doInvoke(invocation, invokers, loadbalance);
}
- 继续F7进入com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);
public FailoverClusterInvoker(Directory<T> directory) {
super(directory);
}
//从这里看
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyinvokers = invokers;
this.checkInvokers(invokers, invocation);
int len = this.getUrl().getMethodParameter(invocation.getMethodName(), "retries", 2) + 1;
if (len <= 0) {
len = 1;
}
RpcException le = null;
List<Invoker<T>> invoked = new ArrayList(invokers.size());
Set<String> providers = new HashSet(len);
for(int i = 0; i < len; ++i) {
if (i > 0) {
this.checkWhetherDestroyed();
copyinvokers = this.list(invocation);
this.checkInvokers(copyinvokers, invocation);
}
Invoker<T> invoker = this.select(loadbalance, invocation, copyinvokers, invoked);
invoked.add(invoker);
RpcContext.getContext().setInvokers(invoked);
try {
//这个是重点了,因为返回了结果, 在这里继续F7
Result result = invoker.invoke(invocation);
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + invocation.getMethodName() + " in the service " + this.getInterface().getName() + " was successful by the provider " + invoker.getUrl().getAddress() + ", but there have been failed providers " + providers + " (" + providers.size() + "/" + copyinvokers.size() + ") from the registry " + this.directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + le.getMessage(), le);
}
Result var12 = result;
return var12;
} catch (RpcException var17) {
if (var17.isBiz()) {
throw var17;
}
le = var17;
} catch (Throwable var18) {
le = new RpcException(var18.getMessage(), var18);
} finally {
providers.add(invoker.getUrl().getAddress());
}
}
throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method " + invocation.getMethodName() + " in the service " + this.getInterface().getName() + ". Tried " + len + " times of the providers " + providers + " (" + providers.size() + "/" + copyinvokers.size() + ") from the registry " + this.directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + (le != null ? le.getMessage() : ""), (Throwable)(le != null && le.getCause() != null ? le.getCause() : le));
}
}
- 继续F7,最终进入 com.alibaba.dubbo.rpc.filter.ProtocolFilterWrapper
package com.alibaba.dubbo.rpc.filter;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.RpcResult;
@Activate(
group = {"consumer"},
order = -10000
)
public class ConsumerContextFilter implements Filter {
public ConsumerContextFilter() {
}
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);
}
RpcResult var4;
try {
//这里就是远程调用,继续F7
RpcResult result = (RpcResult)invoker.invoke(invocation);
RpcContext.getServerContext().setAttachments(result.getAttachments());
var4 = result;
} finally {
RpcContext.getContext().clearAttachments();
}
return var4;
}
}
- 又F7
protected Result doInvoke(Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation)invocation;
String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment("path", this.getUrl().getPath());
inv.setAttachment("version", this.version);
ExchangeClient currentClient;
if (this.clients.length == 1) {
currentClient = this.clients[0];
} else {
currentClient = this.clients[this.index.getAndIncrement() % this.clients.length];
}
try {
boolean isAsync = RpcUtils.isAsync(this.getUrl(), invocation);
boolean isOneway = RpcUtils.isOneway(this.getUrl(), invocation);
int timeout = this.getUrl().getMethodParameter(methodName, "timeout", 1000);
if (isOneway) {
boolean isSent = this.getUrl().getMethodParameter(methodName, "sent", false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture((Future)null);
return new RpcResult();
} else if (isAsync) {
ResponseFuture future = currentClient.request(inv, timeout);
RpcContext.getContext().setFuture(new FutureAdapter(future));
return new RpcResult();
} else {
RpcContext.getContext().setFuture((Future)null);
//这就是最后调用了,继续F7
return (Result)currentClient.request(inv, timeout).get();
}
} catch (TimeoutException var9) {
throw new RpcException(2, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var9.getMessage(), var9);
} catch (RemotingException var10) {
throw new RpcException(1, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var10.getMessage(), var10);
}
}
- 继续多次F7, 进入com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel
//这里就是根了
public ResponseFuture request(Object request, int timeout) throws RemotingException {
if (this.closed) {
throw new RemotingException(this.getLocalAddress(), (InetSocketAddress)null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
} else {
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
DefaultFuture future = new DefaultFuture(this.channel, req, timeout);
try {
this.channel.send(req);
return future;
} catch (RemotingException var6) {
future.cancel();
throw var6;
}
}
}
//ResponseFuture
package com.alibaba.dubbo.remoting.exchange;
import com.alibaba.dubbo.remoting.RemotingException;
public interface ResponseFuture {
Object get() throws RemotingException;
Object get(int var1) throws RemotingException;
void setCallback(ResponseCallback var1);
boolean isDone();
}
2. 总结及思考
1. 可以看到,虽然我们使用起来很简单,但dubbo框架确实封装了很多东西。这其中就是可以学习,参考的地方。
2. 本文使用的是dubbo协议,如果换成别的协议呢?