从 netty-example 入手真的很不戳,学到了
(其实写这个的东西的动力,有一份部分是想增进一下markdown书写规则的了解)
这里放一段org.netty.example.EchoServer的代码(客户端也大同小异),
本文会基于这个用例代码着手源码走读
// Configure the server.
// EventLoopGroup 即集成了Channel(IO)能力的EventExecutorGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// nThread=0会取一个默认值(与机器的可用处理器相关)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {ServerBootstrap b = new ServerBootstrap();// volatile EventLoopGroup group// volatile EventLoopGroup childGroup// 构建的过程基本没有什么逻辑转换在里面,可以说只是赋值而已b.group(bossGroup, workerGroup)// 这里的channel.class包装到ReflectiveChannelFactory的内部属性中// 当需要使用到时,借助该工厂创建出ServerSocketChannel// ServerBootstrap.channelFactory = channelFactory.channel(NioServerSocketChannel.class)// Map, Object> options做了put.option(ChannelOption.SO_BACKLOG, 100)// volatile ChannelHandler handler// 入参类型:ChannelHandler handler.handler(new LoggingHandler(LogLevel.INFO))// volatile ChannelHandler childHandler// 类型也是:ChannelHandler childHandler.childHandler(new ChannelInitializer() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {// 这个channel绑定了pipeline// pipeline又由多个handler组成ChannelPipeline p = ch.pipeline();p.addLast(new LoggingHandler(LogLevel.INFO));p.addLast(new EchoServerHandler());}});// 前面包装到 ReflectChannelFactory 在这里 doBind() 时初始化channel实例// bind() -> io.netty.bootstrap.AbstractBootstrap.initAndRegister -> 返回 ChannelFuture(channel产出)// init:工厂创建channel,初始化channel的childHandler的pipeline,赋值option到channel// register:将channel注册到parentGroup// sync() -> io.netty.util.concurrent.DefaultPromise.await() -> synchronized && waiters ++ChannelFuture f = b.bind(EchoConstants.PORT_SERVER).sync();// Wait until the server socket is closed.f.channel().closeFuture().sync();
} finally {// Shut down all event loops to terminate all threads.bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();
}
至少,通过上面这个服务端代码可以大概地知道相关类有哪些。
建议将其中重要的类做个UML,因为netty是基于juc的线程模型+nio上封装而成,注定会引入一段作者的封装逻辑。
客户端的逻辑基本大同小异
先来段免责声明:
编者默认读者了解jdk.juc的Executor、Thread、ThreadFactory等概念
编者默认读者了解jdk.nio的Buffer、Channel、Selector等概念
编者默认读者了解jdk.net的Socket、Connect等概念

通过翻阅他们api中出、入参类型的变化,再加上命名上的暗示,可以确定:
- 相比
juc.future,netty.future新增了 同步执行(await()、sync()都是synchronized(this),sync()多了rethrow)、监听器集成 的能力
- 相比
netty.future,netty.Promise暴露了 try/set 成功、失败状态 的接口- 相比
netty.future,netty.ChannelFuture将很多相同的接口出、入参类型换了ChannelFuture,埋下了nio的种子
- 相比 以上两者,
netty.ChannelPromise并没有整出啥新活儿,但他是集大成者

值得注意的是:
- netty接入juc的设计:
XxxExecutorGroup同时集成了juc.ExecutorService + Iterator(赋值了Group 群组维护的能力)- netty接入nio的设计:
XxxLoopGroup(图中蓝块) extends XxxExecutorGroup(图中红块),这俩命名接近的Group的区别:引入了ChannelPromise(nio)相关的API- netty的内部逻辑设计:
Xxx(SingleThread) extends XxxGroup(MultiThread),这意味这俩者还存在着职责/角色的差异
仅仅是了解这几个比较重要的类,还是不能做到通读源码的,我们还可以再补一课:
搞清楚NioEventLoopGroup的全参构造中的入参是干嘛的,以及他们的默认值
这有助我们从入口就开始跟着源码,跟紧源码。
搞清楚默认值,以及其接口方法是做什么的就行了
下面每个变量使用三行注释来解释:
public NioEventLoopGroup(// 任务线程数// 默认与当前机器的核心数相关 io.netty.channel.MultithreadEventLoopGroup.DEFAULT_EVENT_LOOP_THREADS// 用于构造 io.netty.util.concurrent.MultithreadEventExecutorGroup.children:EventExecutor[nThreads]int nThreads,// 线程池的实现类// 默认new ThreadPerTaskExecutor(newDefaultThreadFactory())// 也是用于构造 io.netty.util.concurrent.MultithreadEventExecutorGroup.children[i] = newChild(executor, args)Executor executor,// 任务线程的选择策略的工厂// 默认DefaultEventExecutorChooserFactory// EventExecutorChooserFactory chooserFactory,// 用于返回1个轮询连接状态的provider// 默认jdk的工厂(sun.nio.ch.DefaultSelectorProvider)// final SelectorProvider selectorProvider// 轮询连接状态的工厂// 默认io.netty.channel.DefaultSelectStrategyFactory// final SelectStrategyFactory selectStrategyFactory,// 任务拒绝时的处理器// 默认抛异常(io.netty.util.concurrent.RejectedExecutionHandlers.REJECT)// final RejectedExecutionHandler rejectedExecutionHandler,// 任务阻塞队列的工厂// 默认null// 这个先过吧,我也没有注意过这个...final EventLoopTaskQueueFactory taskQueueFactory) {super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory,rejectedExecutionHandler, taskQueueFactory);}
NioEventLoopGroup构造完成后的 ServerBootstrap初始化、构建过程(just赋值,没有啥逻辑的),直接步进到ServerBootstrap.bind()
我错了,有逻辑
顺着NioEventLoopGroup(nThreads)往里狠狠的步进,掠过中间的无逻辑的地方
// io.netty.util.concurrent.MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, java.util.concurrent.Executor, io.netty.util.concurrent.EventExecutorChooserFactory, java.lang.Object...)protected MultithreadEventExecutorGroup(int nThreads, Executor executor,EventExecutorChooserFactory chooserFactory, Object... args) {if (nThreads <= 0) {throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));}if (executor == null) {// 这里赋值默认的线程池(eventLoop的)// 也就是说group下所有的eventLoop的executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());}children = new EventExecutor[nThreads];for (int i = 0; i < nThreads; i ++) {boolean success = false;try {children[i] = newChild(executor, args);success = true;} catch (Exception e) {// TODO: Think about if this is a good exception typethrow new IllegalStateException("failed to create a child event loop", e);} finally {if (!success) {for (int j = 0; j < i; j ++) {children[j].shutdownGracefully();}for (int j = 0; j < i; j ++) {EventExecutor e = children[j];try {while (!e.isTerminated()) {e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);}} catch (InterruptedException interrupted) {// Let the caller handle the interruption.Thread.currentThread().interrupt();break;}}}}}chooser = chooserFactory.newChooser(children);final FutureListener
想了想,还是分成多篇文章吧
上一篇:canvas入门
下一篇:skywalking部署安装