本文分享内容如下:
- 编码和解码入口分析
- 编码流程分析
- 编码-dubbo协议分析
- 解码流程分析
- 解码疑难代码分析
编码和解码入口分析
通过netty支持实现
NettyClient
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
bootstrap = new ClientBootstrap(channelFactory);
// config
// @see org.jboss.netty.channel.socket.SocketChannelConfig
bootstrap.setOption("keepAlive", true);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("connectTimeoutMillis", getTimeout());
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", adapter.getDecoder());//line1
pipeline.addLast("encoder", adapter.getEncoder());// line 2
pipeline.addLast("handler", nettyHandler);
return pipeline;
}
});
}
line 1 和 line 2 添加了解码和编码handler。 他们是从 adapter 中获取的
NettyCodecAdapter的两个重要成员
private final ChannelHandler encoder = new InternalEncoder();
private final ChannelHandler decoder = new InternalDecoder();
encoder 在编码时被调用
private class InternalEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel ch, Object msg) throws Exception {
com.alibaba.dubbo.remoting.buffer.ChannelBuffer buffer =
com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(1024);
NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler);
try {
codec.encode(channel, buffer, msg);
} finally {
NettyChannel.removeChannelIfDisconnected(ch);
}
return ChannelBuffers.wrappedBuffer(buffer.toByteBuffer());
}
}
// 依赖codec实现
//codec在创建NettyCodecAdapter 被传入
public NettyCodecAdapter(Codec2 codec, URL url, com.alibaba.dubbo.remoting.ChannelHandler handler) {
this.codec = codec;//type is DubboCountCodec
this.url = url;//dubbo://127.0.0.1:20880/tuling.dubbo.server.UserService?application=young-app&codec=dubbo&dubbo=2.6.2&heartbeat=60000&interface=tuling.dubbo.server.UserService&loadbalance=roundrobin&methods=findUser,getUser&pid=181756&qos.enable=false®ister.ip=169.254.23.140&side=consumer&timeout=2147483647×tamp=1575983404587
this.handler = handler;//NettyClient
int b = url.getPositiveParameter(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE);
this.bufferSize = b >= Constants.MIN_BUFFER_SIZE && b <= Constants.MAX_BUFFER_SIZE ? b : Constants.DEFAULT_BUFFER_SIZE;
// bufferSize 默认8M
}
这里的codec 类型是DubboCountCodec,在 NettyClient 初始化时被创建。
代码位于AbstractEndpoint
protected static Codec2 getChannelCodec(URL url) {
String codecName = url.getParameter(Constants.CODEC_KEY, "telnet");
//codecName=“dubbo”
if (ExtensionLoader.getExtensionLoader(Codec2.class).hasExtension(codecName)) {//default enter this
return ExtensionLoader.getExtensionLoader(Codec2.class).getExtension(codecName);// return DubboCountCodec
} else {
return new CodecAdapter(ExtensionLoader.getExtensionLoader(Codec.class)
.getExtension(codecName));
}
}
DubboCountCodec分析
private DubboCodec codec = new DubboCodec();
编码部分只是转发给 DubboCodec 执行
public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
codec.encode(channel, buffer, msg);
}
编码部分涉及到 拆包,粘包的处理比较复杂,暂不分析。
DubboCodec分析
重写了decod