dubbo原始碼深度解讀四之remoting模組
前言:remoting模組是遠端通訊模組,相當於Dubbo協議的實現,是一個為Dubbo專案處理底層網路通訊的層。具體結合了netty,mina等進行實現。
一,dubbo-remoting-api
首先結合文件的圖先了解一下基礎介面包的主要類。
1,ChannelHandler是抽象的通道事件處理器,同時注意到它的註解也是SPI
@SPI
public interface ChannelHandler {
void connected(Channel channel) throws RemotingException;
void disconnected(Channel channel) throws RemotingException;
void sent(Channel channel, Object message) throws RemotingException;
void received(Channel channel, Object message) throws RemotingException;
void caught(Channel channel, Throwable exception) throws RemotingException;
}
2,Codec2.介面定義了編碼解碼規範,與廢棄的介面Codec相比,Codec2沒有依賴jdk的輸入輸出流, 以dubbo的ChannelBuffer為核心便於更好的整合(關於各個Codec2的實現類例如DubboCodec,會和rpc模組一起深入解讀)
@SPI
public interface Codec2 {
@Adaptive({Constants.CODEC_KEY})
void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException;
@Adaptive({Constants.CODEC_KEY})
Object decode(Channel channel, ChannelBuffer buffer) throws IOException;
enum DecodeResult {
NEED_MORE_INPUT, SKIP_SOME_INPUT
}
}
3,Transporter
bind 根據URL和ChannelHandler 生成Server, connect 根據URL和ChannelHandler
@SPI("netty")
public interface Transporter {
@Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
Server bind(URL url, ChannelHandler handler) throws RemotingException;
@Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
Client connect(URL url, ChannelHandler handler) throws RemotingException;
}
4,Endpoint。Client和Server都繼承的一個介面類
5,Dispatcher。定義channelHandler對Channel的操作(哪些走執行緒池)
@SPI(AllDispatcher.NAME)
public interface Dispatcher {
@Adaptive({Constants.DISPATCHER_KEY, "dispather", "channel.handler"}) // 後兩個引數為相容舊配置
ChannelHandler dispatch(ChannelHandler handler, URL url);
}
二,服務端整合netty
1,先看下NettyServer的類圖
2,處理流程
其中Netty區域的類,都是擴充套件了了Netty自帶類。
1.1 InternalDecoder:負責TCP層協議的解析,處理TCP粘包。(當然這個解析也包含序列化的處理)。
1.2 InternalEncoder: 協議封裝。
1.3 NettyHandler:客戶通道共享的處理器(請參閱Netty的通道處理器模型),轉換Netty的通道事件到Dubbo事件。
1.4 NettyServer:處理連線數量。
1.5 MultiMessageHandler:多訊息處理。
1.6 HeartbeatHandler:心跳訊息。
1.7 AllChannelHandler:委派業務請求到執行緒池。
3,NettyHandler的實現
繼承org.jboss.netty.channel.SimpleChannelHandler,來處理org.jboss.netty.channel.Channel的連線讀寫事件。此時NettyHandler就可以委託dubbo的com.alibaba.dubbo.remoting.ChannelHandler介面實現來完成具體的功能,在交給com.alibaba.dubbo.remoting.ChannelHandler介面實現之前,需要先將netty自己的org.jboss.netty.channel.Channel channel轉化成上述的NettyChannel。
其實就是相當於轉換Netty的通道事件到Dubbo事件
摘取部分程式碼來看一下就知道了
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler);
try {
if (channel != null) {
channels.put(NetUtils.toAddressString((InetSocketAddress) ctx.getChannel().getRemoteAddress()), channel);
}
//轉換到ChannelHandler的connected
handler.connected(channel);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
}
}
4,NettyServer啟動流程
按照netty自己的API啟動方式,然後依據外界傳遞進來的com.alibaba.dubbo.remoting.ChannelHandler介面實現,創建出NettyHandler,最終對使用者的連線請求的處理全部交給NettyHandler來處理,NettyHandler又交給了外界傳遞進來的com.alibaba.dubbo.remoting.ChannelHandler介面實現。
至此就將所有底層不同的通訊實現全部轉化到了外界傳遞進來的com.alibaba.dubbo.remoting.ChannelHandler介面的實現上了。
而上述Server介面的另一個分支實現HeaderExchangeServer則充當一個裝飾器的角色,為所有的Server實現增添了如下功能:
向該Server所有的Channel依次進行心跳檢測:
- 如果當前時間減去最後的讀取時間大於heartbeat時間或者當前時間減去最後的寫時間大於heartbeat時間,則向該Channel傳送一次心跳檢測
- 如果當前時間減去最後的讀取時間大於heartbeatTimeout,則伺服器端要關閉該Channel,如果是客戶端的話則進行重新連線(客戶端也會使用這個心跳檢測任務)
三,客戶端整合Netty
伺服器端了解了之後,客戶端就也非常清楚了,整體類圖如下:
NettyClient在使用netty的API開啟客戶端之後,仍然使用NettyHandler來處理。還是最終轉化成com.alibaba.dubbo.remoting.ChannelHandler介面實現上了。
我們可以看到這樣整合完成之後,就完全遮蔽了底層通訊細節,將邏輯全部交給了com.alibaba.dubbo.remoting.ChannelHandler介面的實現上了。從上面我們也可以看到,該介面實現也會經過層層裝飾類的包裝,才會最終交給底層通訊。