netty 追踪源码笔记

https://gitee.com/easybao/netty-io-nio.git
链接: https://pan.baidu.com/s/1RvKJe1g6lhXOb4tXiFHA-A 提取码: 9ck3
这是 尚硅谷,韩顺平老师的netty课件:源码, 笔记, 资料都有,感兴趣可以拿来看看
可以看到 netty给了我们一套格式代码,让我们去套用, 我们只需要关注业务逻辑即可,比如编解码处理, 自定义的处理器

    /**
     * 一: netty服务器启动过程
     * serverBootstrap.bind(hostname, port)--->
     * doBind(localAddress);-->
     * 	1.1: initAndRegister();初始化并注册-->
     * 		1.1.1: channelFactory.newChannel();-->ReflectiveChannelFactory.newChannel()--->可以看到这里是使用反射创建的 channel对象,这里的channel对象是JDK的channel,然后netty包装了JDK的channel
     * 		1.1.2: init(channel); 初始化channel,核心是和channelPipeline相关,--->ServerBootstrap.init()-->这个方法可以看出是给channel的 各个map设置值.给 channel的 pipeline添加处理器, channel添加pipeline
     * 			1.1.2.1: pipeline.addLast(handler) 这个是初始化的核心,设置pipeline --->DefaultChannelPipeline.addList()-->checkMultiplicity(handler);这里看到先检查双向链表的容量--------
     * 			           newCtx = newContext(group, filterName(name, handler), handler);这个是创建了一个新的上下文 AbstractChannelHandlerContext对象,这个对象负责ChannelHandler
     * 			           和 ChannelPipeline 之间关联, 之后将这个context添加到双向链表最后, 最后,异步/同步调用callHandlerAdded0(newCtx);
     *
     * 		1.1.3: ChannelFuture regFuture = config().group().register(channel); ----> 这是将 初始化完成的 NioServerSocketChannel 注册到对应的事件循环组中,(bossgroup, workgroup),并返回这个异步执行占位符 future
     *
     * 	1.2: doBind0(regFuture, channel, localAddress, promise);--->channel.bind(localAddress, promise)--->DefaultChannelPipeline.bind() -->tail.bind(localAddress, promise);--->next.invokeBind(localAddress, promise);
     * 	       --->((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);--->DefaultChannelPipeline.bind()-->unsafe.bind(localAddress, promise);-->AbstractChannel.bind()-->doBind(localAddress);
     * 	       --->NioServerSocketChannel.dobind()-->javaChannel().bind(localAddress, config.getBacklog());到这里可以看到是获取到了 java的原生serverSocketChannel,然后绑定端口
     * 	       端口绑定之后,至此整个启动过程结束, 然后服务器进入---> NioEventLoop类protected void run() {} 这是一个无限循环代码,进行监听是否有task进来, runAllTask
     *
     * netty启动过程梳理:
     * 1: 创建二个 EventLoopGroup线程池数组, 数组大小默认 CPU*2, 方便chooser选择线程池时提高性能
     * 2: BootStrap将 boss设置为group属性, 将worker设置为childer属性
     * 3: 通过 bind方法 启动服务器, 内部重要方法是 initAndRegister 和 dobind方法
     * 	3.1: initAndRegiser方法,会反射创建 NioServerSocketChannel,及相关的NIO对象,pipeline unsafe, 同时也为pipeline初始化了 head节点 tail节点
     * 	3.2: 初始化成功之后, dobind方法 最终是调用 NioServerSocketChannel 的dobind方法,,对JDK的 channel 和端口进行绑定,完成绑定之后,完成netty服务器所有启动,并开始后监听连接事件
     *
     *
     *
     *
     * 二: netty接受请求过程源码分析
     * 启动client,发送请求,---->NioEventLoop类的protected void run() {}--->processSelectedKeys();---(selector.selectedKeys() 这个方法返回所有注册在select选择器上的,有事件发生的通道的 sekectedKey集合,通过sekectedKey就可以反向获取到对应通道,然后就可以进行读写操作了,)
     * --->processSelectedKeysOptimized();这是请求发送有数据--->processSelectedKey(k, (AbstractNioChannel) a);---->unsafe.read();这是开始读取数据--->AbstractNioByteChannel.read()---pipeline.fireChannelRead(byteBuf);这里是循环读取数据
     * --->AbstractChannelHandlerContext.invokeChannelRead(head, msg);--->next.invokeChannelRead(m);----->channelRead(this, msg);--->ServerBootstrap.channelRead(ChannelHandlerContext ctx, Object msg)
     * --->childGroup.register(child)这一步是将child 注册到workerGroup事件循环组的线程池中,并添加一个监听器--->继续追reginster方法--->MultithreadEventLoopGroup.register(Channel channel)-->SlngleThreadEventLoop.register()
     * --->promise.channel().unsafe().register(this, promise);---->AbstractChannel.register()--->register0(promise);--->beginRead();---.doBeginRead();--->AbstractNioChannel.doBeginRead()  到这里客户端的连接完成了,接下来是监听读事件
     *
     * netty接受请求过程梳理:
     * 总体流程: 接受连接--->创建一个新的NioSocketChannel--->注册到一个workerEventLoop上---> 注册select Read事件
     * 1: 服务器 轮询Accept事件, 获取事件后调用unsafe的read方法
     * 2: doReadMessages 用于创建NioSocketChannel,这个对象包装JDK的NioChannel客户端
     * 3: 随后执行 pipeline.fireChannelRead方法,开始读取数据
     */

三: ChannelPipeline ChannelHandler ChannelHandlerContext 三者之间的关系

posted @ 2020-11-18 10:13  死不了好气呦  阅读(12)  评论(0编辑  收藏  举报