- Dubbo原始碼分析(一)Dubbo的擴充套件點機制
- Dubbo原始碼分析(二)Dubbo服務釋出Export
- Dubbo原始碼分析(三)Dubbo的服務引用Refer
- Dubbo原始碼分析(四)Dubbo呼叫鏈-消費端(叢集容錯機制)
- Dubbo原始碼分析(五)Dubbo呼叫鏈-服務端
- Dubbo原始碼分析(六)Dubbo通訊的編碼解碼機制
- Dubbo框架的設計細節 (未完,待續)
這篇來分析Dubbo服務端接收消費端請求呼叫的過程,先看一張呼叫鏈的整體流程圖
上面綠色的部分為服務端接收請求部分,大體流程是從ThreadPool-->server-->Exporter-->Filter-->Invoker-->Impl,下面來看原始碼原始碼入口
我們知道Dubbo預設是通過Netty進行網路傳輸,所以這裡的原始碼入口我們應該找到NettyHandler的接收訊息的方法
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());
}
}
複製程式碼
這裡就是服務端接收消費端傳送請求的地方,進入handler.received方法,在AbstractPeer類中
public void received(Channel ch, Object msg) throws RemotingException {
if (closed) {
return;
}
handler.received(ch, msg);
}
複製程式碼
進入到handler.received,最終我們進入AllChannelHandler.received方法中
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
複製程式碼
這裡從執行緒池總來執行請求,我們看到ChannelEventRunnable類,這個類中一定有一個run方法,我們看一下
public void run() {
switch (state) {
case CONNECTED:
try {
handler.connected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case DISCONNECTED:
try {
handler.disconnected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case SENT:
try {
handler.sent(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is " + message, e);
}
break;
case RECEIVED:
try {
handler.received(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is " + message, e);
}
break;
case CAUGHT:
try {
handler.caught(channel, exception);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is: " + message + ", exception is " + exception, e);
}
break;
default:
logger.warn("unknown state: " + state + ", message is " + message);
}
}
複製程式碼
這裡有很多種型別的請求,我們這次是RECEIVED請求,進入handler.received(channel, message)方法,此時的handler=DecodeHandler,先進行解碼,這裡的內容暫時不說,放在後面的解編碼一起說,繼續進入HeaderExchangeHandler.received方法,
public void received(Channel channel, Object message) throws RemotingException {
···
Response response = handleRequest(exchangeChannel, request);
channel.send(response);
} else {
handler.received(exchangeChannel, request.getData());
}
}
} ···
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
}
複製程式碼
執行handleRequest(exchangeChannel, request)方法,這裡是網路通訊接收處理方法,繼續走,進入DubboProtocol.reply方法
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
···
return invoker.invoke(inv);
}
···
}
複製程式碼
進入getInvoker方法,
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
···
DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
···
return exporter.getInvoker();
}
複製程式碼
從exporterMap中獲取所需的exporter,還記不記得這個exporterMap是什麼時候放入值的,在服務端暴露介面的時候,這個是在第二篇中有提到過
然後執行exporter.getInvoker(),現在我們要將exporter轉化為invoeker物件,我們拿到這個invoker物件,並執行invoker.invoke(inv)方法,然後經過8個Filter,最終進入JavassistProxyFactory.AbstractProxyInvoker.doInvoke方法,public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper類不能正確處理帶$的類名
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
複製程式碼
還記得這段程式碼嗎?這個wrapper是什麼?下面這個截圖是在服務暴露的時候,
這個時候執行 wrapper.invokeMethod方法,此時的wrapper就是之前我們動態生成的一個wrapper包裝類,然後進入真正的實現類DemoServiceImpl.sayHello方法,執行完成之後,回到HeaderExchangeHandler.received方法channel.send(response)
複製程式碼
最終把結果通過ChannelFuture future = channel.write(message)發回consumer
消費端接收服務端傳送的執行結果
我們先進入NettyHandler.messageReceived方法,再執行handler.received(channel, e.getMessage()),這個和上面的程式碼是一樣的,繼續進入MultiMessageHandler.received方法,繼續進入ChannelEventRunnable執行緒池,繼續進入DecodeHandler.received解碼,最終進入DefaultFuture.doReceived方法
private void doReceived(Response res) {
lock.lock();
try {
response = res;
if (done != null) {
done.signal();
}
} finally {
lock.unlock();
}
if (callback != null) {
invokeCallback(callback);
}
}
複製程式碼
這裡用到了一個Condition,就是這個done,這裡的done.signal的作用是什麼呢?既然有signal方法,一定還有done.await方法,我們看到這個get方法,
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();
}
複製程式碼
這個裡面有一個done.await方法,貌似這個get方法有點熟悉,在哪裡見過呢,在DubboInvoker.doInvoke()方法中的最後一行,貼程式碼
return (Result) currentClient.request(inv, timeout).get();
複製程式碼
這裡拿到消費端發起請求之後,呼叫了get方法,這個get方法一直阻塞,直到服務端返回結果呼叫done.signal(),這個也是Dubbo的非同步轉同步機制的實現方式,至此,Dubbo的呼叫鏈就分析完了