07.Dubbo 源码解析之服务调用

1. 环境搭建

  • 代码已经上传至 https://github.com/masteryourself/dubbo ,分支名称是 masteryourself-2.7.3-release

  • provider 是 dubbo-demo-xml-provider 工程,启动类是 Application

  • consumer 是 dubbo-demo-xml-consumer 工程,启动类是 Application

2. 源码解析

2.1 流程预览

image

2.1.1 consumer 端
// 1. 由于是动态代理,所以任何方法都会被 InvokerInvocationHandler 的 【invoke】 方法拦截
org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke

	// 1.1(*) 执行 mock 逻辑
	org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke

		// 1.1.1(*) 隐式传参,路由 invokers,初始化负载均衡策略,调用 doInvoke
		org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke

			// 1.1.1.1 查询出经过路由链过滤后的所有 Invokers
			org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#list ->
				org.apache.dubbo.rpc.cluster.directory.AbstractDirectory#list ->
					org.apache.dubbo.registry.integration.RegistryDirectory#doList ->
						// 循环所有的 routers,MockInvokersSelector -> TagRouter -> AppRouter -> ServiceRouter,依次调用 route 方法筛选 invokers
						org.apache.dubbo.rpc.cluster.RouterChain#route

			// 1.1.1.2(*) 失败重试策略
			org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke ->
				// InvokerWrapper,无作用
				org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke ->
					org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke ->
						// 设置 consumer 调用信息
						org.apache.dubbo.rpc.filter.ConsumerContextFilter#invoke ->
							// oninvoke、onreturn、onthrow 处理逻辑
							org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter#invoke ->
								// 监控逻辑
								org.apache.dubbo.monitor.support.MonitorFilter#invoke ->
									// 无作用
									org.apache.dubbo.rpc.listener.ListenerInvokerWrapper#invoke ->
										// 异步转同步,调用 get 方法同步获取结果
										org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker#invoke ->
											// 抽象处理逻辑
											org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke
												
												// 1.1.1.2.1 发送 dubbo 请求,获取结果
												org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke
2.2.2 provider 端
// 1. netty server handler 接收请求
org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run ->
	// 解码 message 信息
	org.apache.dubbo.remoting.transport.DecodeHandler#received ->
		// 判断消息类型,处理请求
		org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received ->
			// 处理请求和响应数据
			org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest ->
				// 调用 【DubboProtocol.ExchangeHandlerAdapter】 处理
				org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter#reply ->
					org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke ->
						// 回声测试 filter
						org.apache.dubbo.rpc.filter.EchoFilter#invoke ->
							// 设置 classLoader
							org.apache.dubbo.rpc.filter.ClassLoaderFilter#invoke ->
								// 泛化调用 filter 处理
								org.apache.dubbo.rpc.filter.GenericFilter#invoke ->
									// 设置 context 上下文参数
									org.apache.dubbo.rpc.filter.ContextFilter#invoke ->
										// 链路追踪
										org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter#invoke ->
											// 服务端响应超时判断
											org.apache.dubbo.rpc.filter.TimeoutFilter#invoke ->
												// 监控
												org.apache.dubbo.monitor.support.MonitorFilter#invoke ->
													// 处理异常
													org.apache.dubbo.rpc.filter.ExceptionFilter#invoke ->
														// 无作用
														org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke ->
															org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker#invoke ->
																// 抽象处理逻辑
																org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke ->
																	// 通过反射调用实现类的方法
																	org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker

2.3 流程详解

2.3.1 MockClusterInvoker#invoke(1.1)
  • org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
public Result invoke(Invocation invocation) throws RpcException {
    Result result = null;

    // 从 url 中获取 mock 对应的值
    String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();

    // 如果没有 value 或者 value 等于 false,则表示没有 mock 逻辑
    if (value.length() == 0 || value.equalsIgnoreCase("false")) {
        //no mock
        result = this.invoker.invoke(invocation);
    }
    // 服务屏蔽:如果是以 force 开头,则表示强制 mock
    else if (value.startsWith("force")) {
        if (logger.isWarnEnabled()) {
            logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
        }
        //force:direct mock
        // mock 逻辑
        result = doMockInvoke(invocation, null);
    }
    // 服务容错:先调用,如果调用失败才会进行 mock 逻辑
    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);
            }

            // mock 逻辑
            result = doMockInvoke(invocation, e);
        }
    }
    return result;
}
2.3.2 AbstractClusterInvoker#invoke(1.1.1)
  • org.apache.dubbo.rpc.cluster.support.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);

    // 初始化负载均衡策略
    LoadBalance loadbalance = initLoadBalance(invokers, invocation);
    RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
    // 调用
    return doInvoke(invocation, invokers, loadbalance);
}
2.3.3 FailoverClusterInvoker#doInvoke
  • org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker
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);

    // 获取调用方法的次数,failover 默认是重试 2 次,+1 表示一共调用三次
    int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
    if (len <= 0) {
        len = 1;
    }
    // retry loop.
    RpcException le = null; // last exception.

    // 表示已经调用过的 Invoker,重试时候避免再次选择到相同的 invoker
    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,它是 RegistryDirectory$InvokerDelegate 类型
        Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);

        // 添加到 invoked 中,表示已经调用过
        invoked.add(invoker);
        RpcContext.getContext().setInvokers((List) invoked);
        try {

            // 调用 invoke 方法,先经过 InvokerWrapper 处理
            Result result = invoker.invoke(invocation);
            
            // 前面的出错只会打印 warn 日志
            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);
}
发布了37 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/masteryourself/article/details/103794912