专栏目录
1-Dubbo架构设计与底层原理-架构设计
2-Dubbo架构设计与底层原理-SPI源码分析
3-Dubbo架构设计与底层原理-自适应拓展原理
4-Dubbo架构设计与底层原理-服务导出源码分析(上)
5-Dubbo架构设计与底层原理-服务导出源码分析(中)
6-Dubbo架构设计与底层原理-服务导出源码分析(下)
7-Dubbo架构设计与底层原理-服务引用源码分析(上)
8-Dubbo架构设计与底层原理-服务引用(下)
9-Dubbo架构设计与底层原理-集群容错之 Directory
10-Dubbo架构设计与底层原理-集群容错之 Router
11-Dubbo架构设计与底层原理-集群容错之 LoadBalance
12-Dubbo服务调用过程-服务调用方式
13-Dubbo服务调用过程源码分析-服务消费方发送请求
14-Dubbo服务调用过程源码分析-服务提供方接收请求
15-Dubbo服务调用过程源码分析-服务提供方响应请求
服务调用过程
Dubbo 服务调用过程比较复杂,包含众多步骤。比如发送请求、编解码、服务降级、过滤器链处理、序列化、线程派发以及响应请求等步骤。重点分析请求的发送与接收、编解码、线程派发以及响应的发送与接收等过程。
Dubbo 服务调用过程:
首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。
服务调用方式
Dubbo 支持同步和异步两种调用方式,其中异步调用还可细分为“有返回值”的异步调用和“无返回值”的异步调用。所谓“无返回值”异步调用是指服务消费方只管调用,但不关心调用结果,此时 Dubbo 会直接返回一个空的 RpcResult。若要使用异步特性,需要服务消费方手动进行配置。默认情况下,Dubbo 使用同步调用方式。
从 DemoService 接口的代理类开始进行分析。Dubbo 默认使用 Javassist 框架为服务接口生成动态代理类,因此需要先将代理类进行反编译才能看到源码。
public class proxy0 implements ClassGenerator.DC, EchoService, DemoService {
// 方法数组
public static Method[] methods;
private InvocationHandler handler;
public proxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
public proxy0() {
}
public String sayHello(String string) {
// 将参数存储到 Object 数组中
Object[] arrobject = new Object[]{
string};
// 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
Object object = this.handler.invoke(this, methods[0], arrobject);
// 返回调用结果
return (String)object;
}
/** 回声测试方法 */
public Object $echo(Object object) {
Object[] arrobject = new Object[]{
object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
}
首先将运行时参数存储到数组中,然后调用 InvocationHandler 接口实现类的 invoke 方法,得到调用结果,最后将结果转型并返回给调用方。
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
// 拦截定义在 Object 类中的方法(未被子类重写),比如 wait/notify
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
// 如果 toString、hashCode 和 equals 等方法被子类重写了,这里也直接调用
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode