Dubbo源码分析之发送请求

本文详细解析了Dubbo框架中的RPC调用流程,包括消费端InvokerInvocationHandler代理请求、RpcInvocation创建、集群Invoker状态检查、负载均衡策略应用、重试机制及异常处理等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消费端操作InvokerInvocationHandler代理发送请求,组装调用类


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    Class<?>[] parameterTypes = method.getParameterTypes();
    if (method.getDeclaringClass() == Object.class) {
        return method.invoke(invoker, args);
    }
    if ("toString".equals(methodName) && parameterTypes.length == 0) {
        return invoker.toString();
    }
    if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
        return invoker.hashCode();
    }
    if ("equals".equals(methodName) && parameterTypes.length == 1) {
        return invoker.equals(args[0]);
    }

    return invoker.invoke(createInvocation(method, args)).recreate();
}

private RpcInvocation createInvocation(Method method, Object[] args) {
    RpcInvocation invocation = new RpcInvocation(method, args);
    if (RpcUtils.hasFutureReturnType(method)) {
        invocation.setAttachment(Constants.FUTURE_RETURNTYPE_KEY, "true");
        invocation.setAttachment(Constants.ASYNC_KEY, "true");
    }
    return invocation;
}

判断是否是mock调用

public Result invoke(Invocation invocation) throws RpcException {
    Result result = null;

    String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
    if (value.length() == 0 || value.equalsIgnoreCase("false")) {
        //no mock
        result = this.invoker.invoke(invocation);
    } else if (value.startsWith("force")) {
        if (logger.isWarnEnabled()) {
            logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
        }
        //force:direct mock
        result = doMockInvoke(invocation, null);
    } else {
        //fail-mock
        try {
            result = this.invoker.invoke(invocation);
        } catch (RpcException e) {
            if (e.isBiz()) {
                throw e;
            }

            if (logger.isWarnEnabled()) {
                logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
            }
            result = doMockInvoke(invocation, e);
        }
    }
    return result;
}

检查集群invoker状态

public Result invoke(final Invocation invocation) throws RpcException {
    checkWhetherDestroyed();

    // binding attachments into invocation.
    Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
    if (contextAttachments != null && contextAttachments.size() != 0) {
        ((RpcInvocation) invocation).addAttachments(contextAttachments);
    }

    List<Invoker<T>> invokers = list(invocation);
    LoadBalance loadbalance = initLoadBalance(invokers, invocation);
    RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
    return doInvoke(invocation, invokers, loadbalance);
}

从注册明细类中获取所有的invoker远程调用,经过路由链路挑选符合的invoker

protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
    return directory.list(invocation);
}

 // Get invokers from cache, only runtime routers will be executed.
invokers = routerChain.route(getConsumerUrl(), invocation);

默认获取随机负载均衡

protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
    if (CollectionUtils.isNotEmpty(invokers)) {
        return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
                .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
    } else {
        return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
    }
}

默认使用失败转移集群调用FailoverClusterInvoker,最多调用三次,从invoker集合中选择本次需要使用的invoker,尽量不使用上次调用失败的invoker。


public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    List<Invoker<T>> copyInvokers = invokers;
    checkInvokers(copyInvokers, invocation);
    String methodName = RpcUtils.getMethodName(invocation);
    int len = getUrl().getMethodParameter(methodName, Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
    if (len <= 0) {
        len = 1;
    }
    // retry loop.
    RpcException le = null; // last exception.
    List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
    Set<String> providers = new HashSet<String>(len);
    for (int i = 0; i < len; i++) {
        //Reselect before retry to avoid a change of candidate `invokers`.
        //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
        if (i > 0) {
            checkWhetherDestroyed();
            copyInvokers = list(invocation);
            // check again
            checkInvokers(copyInvokers, invocation);
        }
        Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
        invoked.add(invoker);
        RpcContext.getContext().setInvokers((List) invoked);
        try {
            Result result = invoker.invoke(invocation);
            if (le != null && logger.isWarnEnabled()) {
                logger.warn("Although retry the method " + methodName
                        + " in the service " + getInterface().getName()
                        + " was successful by the provider " + invoker.getUrl().getAddress()
                        + ", but there have been failed providers " + providers
                        + " (" + providers.size() + "/" + copyInvokers.size()
                        + ") from the registry " + directory.getUrl().getAddress()
                        + " on the consumer " + NetUtils.getLocalHost()
                        + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                        + le.getMessage(), le);
            }
            return result;
        } catch (RpcException e) {
            if (e.isBiz()) { // biz exception.
                throw e;
            }
            le = e;
        } catch (Throwable e) {
            le = new RpcException(e.getMessage(), e);
        } finally {
            providers.add(invoker.getUrl().getAddress());
        }
    }
    throw new RpcException(le.getCode(), "Failed to invoke the method "
            + methodName + " in the service " + getInterface().getName()
            + ". Tried " + len + " times of the providers " + providers
            + " (" + providers.size() + "/" + copyInvokers.size()
            + ") from the registry " + directory.getUrl().getAddress()
            + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
            + Version.getVersion() + ". Last error is: "
            + le.getMessage(), le.getCause() != null ? le.getCause() : le);
}

开始invoker代理包装类调用


class InvokerDelegate<T> extends InvokerWrapper<T>
public Result invoke(Invocation invocation) throws RpcException {
    return invoker.invoke(invocation);
}

监听器包装类


class ListenerInvokerWrapper<T>
public Result invoke(Invocation invocation) throws RpcException {
    return invoker.invoke(invocation);
}

过滤器ConsumerContextFilter,FutureFilter,MonitorFilter


class ProtocolFilterWrapper$1
public Result invoke(Invocation invocation) throws RpcException {
  Result result = filter.invoke(next, invocation);
  if (result instanceof AsyncRpcResult) {
      AsyncRpcResult asyncResult = (AsyncRpcResult) result;
      asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation));
      return asyncResult;
  } else {
      return filter.onResponse(result, invoker, invocation);
  }
}

开始准备远程调用,选择一个客户端,判断同异步以及单双向方式,超时时间

class DubboInvoker<T> extends AbstractInvoker<T>
protected Result doInvoke(final Invocation invocation) throws Throwable {
    RpcInvocation inv = (RpcInvocation) invocation;
    final String methodName = RpcUtils.getMethodName(invocation);
    inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
    inv.setAttachment(Constants.VERSION_KEY, version);

    ExchangeClient currentClient;
    if (clients.length == 1) {
        currentClient = clients[0];
    } else {
        currentClient = clients[index.getAndIncrement() % clients.length];
    }
    try {
        boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
        boolean isAsyncFuture = RpcUtils.isReturnTypeFuture(inv);
        boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
        int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
        if (isOneway) {
            boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
            currentClient.send(inv, isSent);
            RpcContext.getContext().setFuture(null);
            return new RpcResult();
        } else if (isAsync) {
            ResponseFuture future = currentClient.request(inv, timeout);
            // For compatibility
            FutureAdapter<Object> futureAdapter = new FutureAdapter<>(future);
            RpcContext.getContext().setFuture(futureAdapter);

            Result result;
            if (isAsyncFuture) {
                // register resultCallback, sometimes we need the async result being processed by the filter chain.
                result = new AsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
            } else {
                result = new SimpleAsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
            }
            return result;
        } else {
            RpcContext.getContext().setFuture(null);
            return (Result) currentClient.request(inv, timeout).get();
        }
    } catch (TimeoutException e) {
        throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    } catch (RemotingException e) {
        throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

同步进行请求

class ReferenceCountExchangeClient implements ExchangeClient
public ResponseFuture request(Object request, int timeout) throws RemotingException {
    return client.request(request, timeout);
}

class HeaderExchangeClient implements ExchangeClient
public ResponseFuture request(Object request, int timeout) throws RemotingException {
    return channel.request(request, timeout);
}

把请求数据包装为请求Request

class HeaderExchangeChannel implements ExchangeChannel
public ResponseFuture request(Object request, int timeout) throws RemotingException {
    if (closed) {
        throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
    }
    // create request.
    Request req = new Request();
    req.setVersion(Version.getProtocolVersion());
    req.setTwoWay(true);
    req.setData(request);
    DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
    try {
        channel.send(req);
    } catch (RemotingException e) {
        future.cancel();
        throw e;
    }
    return future;
}

通过netty开始进行发送请求

class AbstractPeer implements Endpoint, ChannelHandler
public void send(Object message) throws RemotingException {
    send(message, url.getParameter(Constants.SENT_KEY, false));
}

class AbstractChannel extends AbstractPeer implements Channel
public void send(Object message, boolean sent) throws RemotingException {
    if (isClosed()) {
        throw new RemotingException(this, "Failed to send message "
                + (message == null ? "" : message.getClass().getName()) + ":" + message
                + ", cause: Channel closed. channel: " + getLocalAddress() + " -> " + getRemoteAddress());
    }
}

把请求写入通道,后续会进行编码发送

class NettyChannel extends AbstractChannel
public void send(Object message, boolean sent) throws RemotingException {
    super.send(message, sent);

    boolean success = true;
    int timeout = 0;
    try {
        ChannelFuture future = channel.writeAndFlush(message);
        if (sent) {
            timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
            success = future.await(timeout);
        }
        Throwable cause = future.cause();
        if (cause != null) {
            throw cause;
        }
    } catch (Throwable e) {
        throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
    }

    if (!success) {
        throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
                + "in timeout(" + timeout + "ms) limit");
    }
}

对写事件进行处理,我们添加监听器以确保我们的写事件是正确的。如果我们的写事件有错误(在大多数情况下编码器失败),我们需要直接返回请求,而不是阻塞调用进程,依次经过各个处理器对发送事件做处理。

class NettyClientHandler extends ChannelDuplexHandler
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    super.write(ctx, msg, promise);
    final NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
    final boolean isRequest = msg instanceof Request;

    // We add listeners to make sure our out bound event is correct.
    // If our out bound event has an error (in most cases the encoder fails),
    // we need to have the request return directly instead of blocking the invoke process.
    promise.addListener(future -> {
        try {
            if (future.isSuccess()) {
                // if our future is success, mark the future to sent.
                handler.sent(channel, msg);
                return;
            }

            Throwable t = future.cause();
            if (t != null && isRequest) {
                Request request = (Request) msg;
                Response response = buildErrorResponse(request, t);
                handler.received(channel, response);
            }
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    });
}

 

### Dubbo源码分析 #### 负载均衡器选择 Invoker 的详细逻辑 在 Dubbo 框架中,负载均衡器的核心作用是在多个可用的服务提供者之间分配请求流量。具体来说,在负载均衡器选择 `Invoker` 的过程中,Dubbo 首先会获取当前服务的所有可用提供者列表,并通过指定的负载均衡策略来决定最终调用哪个具体的 `Invoker` 实例[^1]。 以下是负载均衡器的主要工作流程: - **获取候选 Provider 列表**:从注册中心拉取所有在线的服务提供方地址。 - **过滤不可用实例**:移除那些因网络异常或其他原因而无法正常工作的服务实例。 - **执行负载均衡算法**:根据配置的负载均衡策略(如随机、轮询或一致性哈希),计算并返回目标 `Invoker`。 #### 配置管理机制解析 Dubbo 支持多种方式加载配置信息,其中一种常见的方式是通过 ZooKeeper 作为配置中心。为了确保系统的高可靠性和灵活性,Dubbo 提供了一套完善的配置优先级规则: 1. **本地配置覆盖远程配置**:如果同一参数既定义在本地也存在远端,则以本地为准[^2]。 2. **默认值补充缺失字段**:当某些必要选项未被显式声明时,默认设置会被自动填充进去。 这种设计不仅简化了运维操作难度,还增强了应对突发状况的能力——即使连接不上外部存储库也能维持基本功能运转。 #### 请求处理链路剖析 当客户端发起一次 RPC 调用后,该请求经过一系列处理器层层传递直至抵达实际业务方法之前经历了复杂的转换过程。以下列举几个关键环节及其职责所在: - **解码阶段 (DecodeHandler)** :负责将字节流还原成 Java 对象形式以便后续步骤能够理解其含义; - **头部交换协议适配层(HeaderExchangeHandler)** :主要完成消息头部分的数据组装拆分任务; - **核心协议实现类(DubboProtocol.requestHandler)** :承担着最为繁重的工作量,包括但不限于序列化反序列化控制以及线程池调度安排等等[^3]. 以上各组件紧密协作共同构建起了完整的通信桥梁结构图谱如下所示: ```mermaid sequenceDiagram participant Client as 客户端 participant NettyServer as Netty服务器 participant DecodeHandler as 解码处理器 participant HeaderExchangeHandler as 头部交换处理器 participant RequestHandler as 请求处理器 Client->>NettyServer: 发送数据包 activate NettyServer Note over NettyServer: 接收到原始二进制数据\n触发回调函数 NettyServer->>DecodeHandler: 执行decode()方法 activate DecodeHandler DecodeHandler-->>NettyServer: 返回Java对象表示的消息体 deactivate DecodeHandler NettyServer->>HeaderExchangeHandler: 继续向下游转发已解析好的Request实体 activate HeaderExchangeHandler HeaderExchangeHandler->>RequestHandler: 委托给requestHandler进一步加工 activate RequestHandler ... 更深层次的具体事务逻辑 ... end ``` #### 动态上下线通知机制探讨 对于动态调整集群规模场景下的优雅停机需求而言,Dubbo 设计了一个简单有效的解决方案即主动注销机制。每当某个 Provider 准备退出运行环境前都会提前告知 Registry 自己即将消失的事实;随后 Consumer 端订阅到这一变更事件之后便会及时更新内部缓存状态从而避免继续尝试访问已经失效的目标资源[^4]。 --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值