dubbo源碼5 -- 消費者發送數據調用鏈

List<Config> configs = testService.findByCategory(“aa”);
調用test項目的com.test.ITestService.findByCategory(String category), 並且需要返回結果List<Config>

消費端發送數據

List<Config> configs = testService.findByCategory(“aa”);
主要是服務A發送testService.findByCategory(“aa”) -》 服務B,並且等待服務B的響應

消費端調用Invoker:
在這裏插入圖片描述

  • testService是ReferenceBean初始化時創建的代理對象Proxy$0
  • 代理對象Proxy$0攔截方法,調用InvokerInvocationHandler中的invoke()
    並且將method, args包裝成RpcInvocation
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(new RpcInvocation(method, args)).recreate();
  }
  • InvokerInvocationHandler交給invoker處理 (MockClusterInvoker)
    調用服務B的方法出錯時,忽略異常,調用mock返回結果
    1. 沒有配置mock交給下一個invoker處理
    2. 帶有force,只調用mock方法。直接返回結果
    3. 執行服務B的方法,出現異常。調用mock方法返回結果
public Result invoke(Invocation invocation) throws RpcException {
		Result result = null;
        //是否配置了mock
        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim(); 
        //交給下一個invoker處理
        if (value.length() == 0 || value.equalsIgnoreCase("false")){
        	result = this.invoker.invoke(invocation);
        //強制使用mock
        } else if (value.startsWith("force")) {
        	result = doMockInvoke(invocation, null);
        } else {
            //調用方法出現錯誤時,才走mock
        	try {
        		result = this.invoker.invoke(invocation);
        	}catch (RpcException e) {
				if (e.isBiz()) {
					throw e;
				} else {
					result = doMockInvoke(invocation, e);
				}
			}
        }
        return result;
	}

直接從directory中取出mockInvokers列表

private Result doMockInvoke(Invocation invocation,RpcException e){
		Result result = null;
    	Invoker<T> minvoker ;
    	
    	List<Invoker<T>> mockInvokers = directory.list(invocation);
		if (mockInvokers == null || mockInvokers.size() == 0){
			minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
		} else {
			minvoker = mockInvokers.get(0);
		}
		try {
			result = minvoker.invoke(invocation);
		} catch (RpcException me) {
			if (me.isBiz()) {
				result = new RpcResult(me.getCause());
			} else {
				throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
			}
		} catch (Throwable me) {
			throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
		}
		return result;
    }
  • 集羣容錯: FailoverClusterInvoker
    默認是FailoverClusterInvoker,根據配置來確定使用哪個。
    集羣容錯:失敗的時候自動切換並重試其他服務器。 通過retries=2。 來設置重試次數。具體查看dubbo集羣容錯章節

從zookeeper獲取集羣中的提供者列表,選擇負載均衡類型,獲取出一個Invoker
在這裏插入圖片描述

  • RegistryDirectory
  1. 從methodInvokerMap獲取提供者的invoker列表()
public List<Invoker<T>> doList(Invocation invocation) {
  if (forbidden) {
      throw new RpcException();
  }
  List<Invoker<T>> invokers = null;
  //從本地緩存invoker列表中獲取
  Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; 
  if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
      String methodName = RpcUtils.getMethodName(invocation);
      Object[] args = RpcUtils.getArguments(invocation);
      //根據方法名稱和參數獲取invoker列表
      if (args != null && args.length > 0 && args[0] != null
              && (args[0] instanceof String || args[0].getClass().isEnum())) {
          invokers = localMethodInvokerMap.get(methodName + "." + args[0]);
      }
      if (invokers == null) {
          invokers = localMethodInvokerMap.get(methodName);
      }
      if (invokers == null) {
          invokers = localMethodInvokerMap.get(Constants.ANY_VALUE);
      }
      if (invokers == null) {
          Iterator<List<Invoker<T>>> iterator = localMethodInvokerMap.values().iterator();
          if (iterator.hasNext()) {
              invokers = iterator.next();
          }
      }
  }
  return invokers == null ? new ArrayList<Invoker<T>>(0) : invokers;
}
  1. 確定負載均衡類型,選擇出一個invoker
    默認是RandomLoadBalance: 先按照權重隨機抽取,權重相同,隨機抽取
    具體查看dubbo 負載均衡章節
  • RegistryDirectory.InvokerDelegate

調用本地的invoker(提供者invoker)方法
在這裏插入圖片描述
上面已經從本地的invoker列表中獲取到具體的invoker。

  • InvokerDelegate: 只是個包裝,什麼也不做

  • ProtocolFilterWrapper
    輪詢執行customer的Filter的調用鏈. 具體查看執行customer的Filter的調用鏈

  • DubboInvoker

  1. 獲取客戶端連接
   ExchangeClient currentClient;
     if (clients.length == 1) {
         currentClient = clients[0];
     } else {
         currentClient = clients[index.getAndIncrement() % clients.length];
     }
  1. 這裏是需要等待服務B的響應結果的
 //同步等待返回值
 RpcContext.getContext().setFuture(null);
 return (Result) currentClient.request(inv, timeout).get();

調用DefaultFuture.get()。當前線程處理等待(服務A等待服務B的響應結果),只有當服務B響應結果或者超時,線程才被喚醒

 public Object get(int timeout) throws RemotingException {
        if (timeout <= 0) {
            timeout = Constants.DEFAULT_TIMEOUT;
        }
        if (!isDone()) {
            long start = System.currentTimeMillis();
            lock.lock();
            try {
                while (!isDone()) {
                    done.await(timeout, TimeUnit.MILLISECONDS);
                    if (isDone() || System.currentTimeMillis() - start > timeout) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            if (!isDone()) {
                throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
            }
        }
        return returnFromResponse();
    }

netty客戶端處理
在這裏插入圖片描述

  • 中間省略
  • HeaderExchangeChannel
  Request req = new Request();
  req.setVersion("2.0.0");
  req.setTwoWay(true);
  req.setData(request);
  DefaultFuture future = new DefaultFuture(channel, req, timeout);
  try {
      channel.send(req);
  } catch (RemotingException e) {
      future.cancel();
      throw e;
  }
  return future;
  1. 初始化Request :TwoWay爲true,代碼需要服務B響應結果
  2. 創建DefaultFuture
    將當前request中的id存在FUTURES中。
 public DefaultFuture(Channel channel, Request request, int timeout) {
    this.channel = channel;
    this.request = request;
    this.id = request.getId();
    this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
    FUTURES.put(id, this);
    CHANNELS.put(id, channel);
}
  1. 交給下一個channel發送數據
  • NettyChannel: 最終調用netty中的channel.write(message). 交給io處理
public void send(Object message, boolean sent) throws RemotingException {
   super.send(message, sent);

    boolean success = true;
    int timeout = 0;
    try {
        ChannelFuture future = channel.write(message);
        if (sent) {
            timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
            success = future.await(timeout);
        }
        Throwable cause = future.getCause();
        if (cause != null) {
            throw cause;
        }
    } catch (Throwable e) {
        throw new RemotingException();
    }

    if (!success) {
        throw new RemotingException();
    }
}

提供端接收到數據,處理結果

netty處理請求1
在這裏插入圖片描述

  • NettyHandler
    服務端專門用來處理客戶端io之間的處理事件
    接收到消息,直接給下一個handler處理
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
      NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler);
      try {
          handler.received(channel, e.getMessage());
      } finally {
          NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
      }
  }
  • MultiMessageHandler: 處理多個消息

  • HeartbeatHandler:處理與消費端之間的心跳數據
    設置讀取時間、心跳請求,發送心跳數據給消費端、心跳響應,不處理

public void received(Channel channel, Object message) throws RemotingException {
    //設置讀取時間
    channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
    //心跳請求
   if (isHeartbeatRequest(message)) {
       Request req = (Request) message;
       if (req.isTwoWay()) {
          //發送心跳數據給消費端
           Response res = new Response(req.getId(), req.getVersion());
           res.setEvent(Response.HEARTBEAT_EVENT);
           channel.send(res);
       }
       return;
   }
   //心跳響應,不處理
   if (isHeartbeatResponse(message)) {
       return;
   }
   handler.received(channel, message);
}

netty處理請求2

在這裏插入圖片描述

  • 線程模型
    提供端接收到消費端的請求,將請求交給線程模型去處理
    all (默認): 在連接、斷開連接、接收數據以及連接出現異常時都是交給線程池去處理的。而發送數據直接交給IO去處理
    direct: 所有消息都不派發到線程池,全部在 IO 線程上直接執行。
    message: 只有在接收數據才交給線程池,別的還是交給ChannelHandler 去處理
    connection: 在 IO 線程上,將連接斷開事件放入隊列,有序逐個執行,其它消息派發到線程池
    線程池由自己創建
    execution:和All類似
    具體查看duubo線程模型
  • DecodeHandler: 解碼
    當收到消費端的請求,需要將
    這裏的message是Request
 public void received(Channel channel, Object message) throws RemotingException {
   if (message instanceof Decodeable) {
         decode(message);
     }

     if (message instanceof Request) {
         decode(((Request)message).getData());
     }

     if (message instanceof Response) {
         decode( ((Response)message).getResult());
     }

     handler.received(channel, message);
 }

netty執行請求併發送響應給消費端

在這裏插入圖片描述

  • HeaderExchangeHandle
    isEvent:false, isTwoWay:true
    Request request = (Request) message;
    if (request.isEvent()) {
         handlerEvent(channel, request);
     } else {
         if (request.isTwoWay()) {
             Response response = handleRequest(exchangeChannel, request);
             channel.send(response);
         } else {
             handler.received(exchangeChannel, request.getData());
         }
     }
  1. 初始化Response(id與request的id一致), 調用下一個handler處理並返回結果
Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
    Response res = new Response(req.getId(), req.getVersion());
    Object msg = req.getData();
    try {
        Object result = handler.reply(channel, msg);
        res.setStatus(Response.OK);
        res.setResult(result);
    } catch (Throwable e) {
        res.setStatus(Response.SERVICE_ERROR);
        res.setErrorMessage(StringUtils.toString(e));
    }
    return res;
}

2) 發送響應數據給消費端

channel.send(response);

這裏的channel是NettyChannel. 調用原生netty的channel發送

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

    boolean success = true;
    int timeout = 0;
        ChannelFuture future = channel.write(message);
        if (sent) {
            timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
            success = future.await(timeout);
        }
        Throwable cause = future.getCause();
        if (cause != null) {
            throw cause;
        }
}

提供端的invoker執行請求
在這裏插入圖片描述

  • DubboProtocol.ExchangeHandlerAdapter
    從本地exporterMap中獲取invoker(在ServiceBean初始化時,創建的invoker)
 public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
      if (message instanceof Invocation) {
            Invocation inv = (Invocation) message;
            Invoker<?> invoker = getInvoker(channel, inv);
            RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
            return invoker.invoke(inv);
        }
        throw new RemotingException();
    }
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
   boolean isCallBackServiceInvoke = false;
    boolean isStubServiceInvoke = false;
    int port = channel.getLocalAddress().getPort();
    String path = inv.getAttachments().get(Constants.PATH_KEY);
    isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(Constants.STUB_EVENT_KEY));
    if (isStubServiceInvoke) {
        port = channel.getRemoteAddress().getPort();
    }
    
    isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke;
    if (isCallBackServiceInvoke) {
        path = inv.getAttachments().get(Constants.PATH_KEY) + "." + inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY);
        inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
    }
    String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));

    DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);

    if (exporter == null)
        throw new RemotingException();

    return exporter.getInvoker();
}
  • ListenerInvokerWrapper:不處理

  • ProtocolFilterWrapper : 依次執行provider方的Filter
    具體查看執行provider方的Filter

  • JavassistProxyFactory.AbstractProxyInvoker

@Override
   protected Object doInvoke(T proxy, String methodName,
                              Class<?>[] parameterTypes,
                              Object[] arguments) throws Throwable {
        return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
    }
  • wrapper交給代理類來執行
    這個wrapper是動態生成的,根據接口來生成的。最終執行 testService.findByCategory(“aa”)
    而proxy就是<dubbo:service …ref="" />中的ref
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
    com.test.ITestService w;
    try {
      w = ((com.test.ITestService) $1);
    } catch (Throwable e) {
      throw new IllegalArgumentException(e);
    }
    try {
      if ("test".equals($2) && $3.length == 1) {
        return ($w) w.test((java.lang.String) $4[0]);
      }
    } catch (Throwable e) {
      throw new java.lang.reflect.InvocationTargetException(e);
    }
    throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("");
  }

消費端收到數據,返回給用戶數據

在這裏插入圖片描述
消費端收到提供端的響應數據後,交給NettyHandler處理
依次執行HeartbeatHandler(是否心跳數據) -> 線程模型(交給線程池處理)-
在這裏插入圖片描述
然後解碼-> 將處理結果response賦值給變量,喚醒線程(客戶端)。將數據返回給用戶

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章