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返回結果- 沒有配置mock交給下一個invoker處理
- 帶有force,只調用mock方法。直接返回結果
- 執行服務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
- 從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;
}
- 確定負載均衡類型,選擇出一個invoker
默認是RandomLoadBalance: 先按照權重隨機抽取,權重相同,隨機抽取
具體查看dubbo 負載均衡章節
- RegistryDirectory.InvokerDelegate
調用本地的invoker(提供者invoker)方法
上面已經從本地的invoker列表中獲取到具體的invoker。
-
InvokerDelegate: 只是個包裝,什麼也不做
-
ProtocolFilterWrapper
輪詢執行customer的Filter的調用鏈. 具體查看執行customer的Filter的調用鏈 -
DubboInvoker
- 獲取客戶端連接
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
- 這裏是需要等待服務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;
- 初始化Request :TwoWay爲true,代碼需要服務B響應結果
- 創建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);
}
- 交給下一個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());
}
}
- 初始化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賦值給變量,喚醒線程(客戶端)。將數據返回給用戶