dubbo 消费者是如何完成一次请求的

496 阅读3分钟

当我们获取到引用接口的代理时

//调用
demoService.sayHello("world"); 

会进入到

//InvokerInvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcInvocation invocation;
       //封装请求参数
        invocation = new RpcInvocation(method, args);
        return invoker.invoke(invocation).recreate();
    }

然后到

//MockClusterInvoker 获取代理时new进来的
//根据不同的 "mock" 配置,调用真正的Invoker 和 Mock 的 Invoker
    public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;
            //invoker,directory是在返回代理时new MockClusterInvoker 放入的
        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), "mock", Boolean.FALSE.toString()).trim();
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            //1.no mock // 调用原 Invoker ,发起 RPC 调用
            result = this.invoker.invoke(invocation);//进入AbstractClusterInvoker

//AbstractClusterInvoker
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);
        }
        // 获得所有服务提供者 Invoker 集合
        List<Invoker<T>> invokers = list(invocation);//-->进入6 7
        //获得 LoadBalance 对象
        LoadBalance loadbalance = initLoadBalance(invokers, invocation);//8
        // 设置调用编号,若是异步调用
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        // 执行调用(子Cluster的Invoker实现类的服务调用的差异逻辑。)
        return doInvoke(invocation, invokers, loadbalance);
    }

//FailoverClusterInvoker
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyinvokers = invokers;
        checkInvokers(copyinvokers, invocation);// 检查copyinvokers即可用Invoker集合是否为空,如果为空,那么抛出异常
        String methodName = RpcUtils.getMethodName(invocation);
        // 得到最大可调用次数:最大可重试次数+1,默认最大可重试次数Constants.DEFAULT_RETRIES=2
        int len = getUrl().getMethodParameter(methodName, "retries", 2) + 1;
        if (len <= 0) {
            len = 1;
        }
        // retry loop.
        RpcException le = null; //  保存最后一次调用的异常
        // 保存已经调用过的Invoker
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        // failover机制核心实现:如果出现调用失败,那么重试其他服务器
        for (int i = 0; i < len; i++) {
            if (i > 0) {
                //i > 0进行重新选择,避免重试时,候选 Invoker 集合,已发生变化。
                checkWhetherDestroyed();
                copyinvokers = list(invocation);
                // check again
                checkInvokers(copyinvokers, invocation);
            }
            // 根据负载均衡机制从copyinvokers中选择一个Invoker
            Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);//9
            // 保存每次调用的Invoker
            invoked.add(invoker);
            // 设置已经调用的 Invoker 集合,到 Context 中
            RpcContext.getContext().setInvokers((List) invoked);
            try {// RPC 调用得到 Result
                Result result = invoker.invoke(invocation);

//InvokerWrapper
 public Result invoke(Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

//ListenerInvokerWrapper
 public Result invoke(Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

//ProtocolFilterWrapper
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class)
                                .getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
            for (int i = filters.size() - 1; i >= 0; i--) {//倒叙循环
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {
                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);}
                    public Class<T> getInterface() {return invoker.getInterface();}
                    public URL getUrl() {return invoker.getUrl();}
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }
                    public void destroy() {invoker.destroy();}
                    public String toString() {return invoker.toString();
                    }
                };
            }//for结束
        }//if结束
        return last;
    }

//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);
        }
        try {
            // TODO should we clear server context?
            RpcContext.removeServerContext();
            return postProcessResult(invoker.invoke(invocation), invoker, invocation);
        } finally {
            // TODO removeContext? but we need to save future for RpcContext.getFuture() API. If clear attachments here, attachments will not available when postProcessResult is invoked.
            RpcContext.getContext().clearAttachments();
        }
    }

//FutureFilter
public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
        fireInvokeCallback(invoker, invocation);
        return postProcessResult(invoker.invoke(invocation), invoker, invocation);
    }

//MonitorFilter
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) {
            RpcContext context = RpcContext.getContext(); // provider must fetch context before invoke() gets called
            String remoteHost = context.getRemoteHost();
            long start = System.currentTimeMillis(); // record start timestamp
            getConcurrent(invoker, invocation).incrementAndGet(); // count up
            try {
                Result result = invoker.invoke(invocation); // proceed invocation chain
                collect(invoker, invocation, result, remoteHost, start, false);
                return result;
            } catch (RpcException e) {
                collect(invoker, invocation, null, remoteHost, start, true);
                throw e;
            } finally {
                getConcurrent(invoker, invocation).decrementAndGet(); // count down
            }
        } else {
            return invoker.invoke(invocation);
        }
    }

//AbstractInvoker
public Result invoke(Invocation inv) throws RpcException {
        if (destroyed.get()) {
            throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost()
                    + " use dubbo version " + Version.getVersion()
                    + " is DESTROYED, can not be invoked any more!");
        }
        RpcInvocation invocation = (RpcInvocation) inv;
        invocation.setInvoker(this);
        if (attachment != null && attachment.size() > 0) {
            invocation.addAttachmentsIfAbsent(attachment);
        }
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        if (contextAttachments != null && contextAttachments.size() != 0) {
            invocation.addAttachments(contextAttachments);
        }
        if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
            invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
        }
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);


        try {
            return doInvoke(invocation);

//DubboInvoker
currentClient.request(inv, timeout).get();
//ReferenceCountExchangeClient
  public ResponseFuture request(Object request, int timeout) throws RemotingException {
        return client.request(request, timeout);
    }
//HeaderExchangeClient
 public ResponseFuture request(Object request, int timeout) throws RemotingException {
        return channel.request(request, timeout);
    }
 channel.send(req);
//AbstractPeer
public void send(Object message) throws RemotingException {
        send(message, url.getParameter(Constants.SENT_KEY, false));
    }
//AbstractClient
 public void send(Object message, boolean sent) throws RemotingException {
        if (send_reconnect && !isConnected()) {
            connect();// 未连接时,开启重连功能,则先发起连接
        }
        Channel channel = getChannel();// 发送消息
        //TODO Can the value returned by getChannel() be null? need improvement.
        if (channel == null || !channel.isConnected()) {
            throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
        }
        channel.send(message, sent);
    }
//NettyChannel
     ChannelFuture future = channel.writeAndFlush(message);

最后。附上一张图