上篇文章从DubboBootstrap start方法一直分析到了RegistryProtocol register方法,其中提到,RegistryProtocol doLocalExport最终会启动Netty服务用来处理客户端的请求,本篇文章,将会详细分析下上述过程。
一、时序图
老规矩,有图先看图,以上即为RegistryProtocol到NettyTransporter的时序图,最终由NettyTransporter创建NettyServer对象。
二、步骤详解
拿出一些关键的步骤,进行源码分析。
1.步骤2
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
String key = getCacheKey(originInvoker);
return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
});
}
可以看到,核心方法则是调用protocol.export方法,看过前文的同学应该明白,此刻的protocol已经是装饰后的Protocol$Adaptive对象了,由于默认用的dubbo协议,经历层层的Wrapper后,最终调用DubboProtocol的export方法
2.步骤7
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
... ...
// 启动netty
openServer(url);
optimizeSerialization(url);
// 根据invoker中配置的optimizer参数获取扩展的自定义序列化处理类
return exporter;
}
核心方法为openServer方法
3.步骤8
private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client can export a service which's only for server to invoke
boolean isServer = url.getParameter(IS_SERVER_KEY, true);
if (isServer) {
ProtocolServer server = serverMap.get(key);
if (server == null) {
synchronized (this) {
server = serverMap.get(key);
if (server == null) {
serverMap.put(key, createServer(url));
}
}
} else {
// server supports reset, use together with override
server.reset(url);
}
}
}
先获取到当前机器的ip地址,然后判断是否是服务端,如果当前是服务端,则首先会从缓存中获取,获取不到,createServer去创建。
4.步骤13
这里提一句,Transporters对象本身也是个SPI,因此,Dubbo也会为其生成个Adaptive类,默认实现为NettyTransporter
@SPI("netty")
public interface Transporter {
RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;
Client connect(URL url, ChannelHandler handler) throws RemotingException;
}
5.步骤14
public class NettyTransporter implements Transporter {
public static final String NAME = "netty3";
@Override
public RemotingServer bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
@Override
public Client connect(URL url, ChannelHandler listener) throws RemotingException {
return new NettyClient(url, listener);
}
}
bind方法则是直接new了NettyServer对象
三、NettyServer解析
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
bootstrap = new ServerBootstrap(channelFactory);
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
channels = nettyHandler.getChannels();
// https://issues.jboss.org/browse/NETTY-365
// https://issues.jboss.org/browse/NETTY-379
// final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("backlog", getUrl().getPositiveParameter(BACKLOG_KEY, Constants.DEFAULT_BACKLOG));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", adapter.getDecoder());
pipeline.addLast("encoder", adapter.getEncoder());
pipeline.addLast("handler", nettyHandler);
return pipeline;
}
});
// bind
channel = bootstrap.bind(getBindAddress());
}
NettyServer的核心方法doOpen,标准的Netty server实现,这里可以看到,boss线程和worker线程,使用的都是无界的线程池,毕竟RPC服务,还是要保证服务端的可用性。
指定decoder和encoder以及handler,这里就先不展开讲了,后面分析服务端处理请求的时候会详细分析下其实现。
四、小节
本文章主要分析了从RegistryProtocol一直到Netty启动的过程中的源码设计,可以看到netty部分中最关键的三个组件为decoder和encoder以及handler,后面分析处理客户端请求的时候会着重分析下。本篇其实还遗留了一点,比如netty启动后,是如何把服务注册到注册中心上的,接下来的文章会详细分析下相关设计。