前言: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依次进行心跳检测:
三,客户端集成Netty
服务器端了解了之后,客户端就也非常清楚了,整体类图如下:
NettyClient在使用netty的API开启客户端之后,仍然使用NettyHandler来处理。还是最终转化成com.alibaba.dubbo.remoting.ChannelHandler接口实现上了。
我们可以看到这样集成完成之后,就完全屏蔽了底层通信细节,将逻辑全部交给了com.alibaba.dubbo.remoting.ChannelHandler接口的实现上了。从上面我们也可以看到,该接口实现也会经过层层装饰类的包装,才会最终交给底层通信。