• 源码解析-Netty源码之Bootstrap创建,初始化Channel,Pipeline,handler


     从Netty官方给出的example包着手点分析,echo 回声,也就是客户端传什么,服务端传回什么

    先从客户端开始看

     

    属性,ip地址,端口号,数据大小之类的 四个写死了的

     判断ssl是否为空,来决定是否需要初始化SslContext (可以理解为一些客户端的初始化配置,我们的例子中默认是null)

    下面重点来了,前面暂时都可以忽略

    核心点几步:

    1. 创建一个线程池组group;  //初始化线程池系列 包括group loop的初始化,配置了chooser,以及引用EventExecutor代表loop

    2. 创建一个客户端Bootstrap;

    3. 加入线程池组,

    4. 加入socketChannel,     //创建channelFactory 将来用来创建NioSocketChannel

    5. 定义了ChannelInitializer,重写initChannel()方法,调用Channel的pipeline,加入了head,tail和自定义的handel;

    6. 异步connect;       //这一步做的事比较多,new一个channel,初始化一个pipeline,将ChannelInitializer内部的handler全部加入到新的pipeline。从group中拿一个loop 将channel注入到loop中,启动loop线程,将channel注册到selector上

    7. 关闭channel;

    8. 关闭线程池组group;

    这一篇重点分析第2,3,4,5步 

    这些不是最重点的,但是也是必要的

    本篇简单介绍一下初始化的过程,包括创建BootStrap 初始化handel,定义channelFactory等过程

    ---

    new Bootstrap()

    ServerBootstrap 类用于创建服务端实例,Bootstrap 用于创建客户端实例

    可以理解为这是Netty留给外界调用的一个入口,大大简化了我们对Netty的使用

    源码走起

     

     bootstrap继承自顶层Channel,至于Channel之后会仔细分析,暂时认知他就是个管道吧,每一次连接就会创建一个channel,然后会不断地通过channel传输数据然后传给pipeline处理

    bootstrap的定位就是一个客户端,封装了connect,group,channel,handel等方法,将这些组件组装在一起供我们使用

    bootstrap.group()

     

    非常非常的简单,就是把之前初始化的group配置进来,self()就是将配置完的自己返回,用来继续配置(builder模式)

    bootstrap.channel()

    传进来未知类型的class类型,封装成ChannelFactory然后存起来,以后需要这个class的时候通过反射实例化出来。

    落地其实就是传入个NioSocketChannel ,把他封装成ReflectiveChannelFactory然后存起来,需要NioSocketChannel的时候 就会反射的方式通过构造方法 实例化一个NioSocketChannel出来

    这一步判断传进来的class无参构造方法是否存在

     将包装好的ReflectiveChannelFactory存起来,返回bootstrap

    new ChannelInitializer<SocketChannel>(){ initChannel() }    这一步比较重点,定义ChannelPipeline,加入各种handler

    ChannelInitializer这个东西就是将来辅助生产pipeline的

     

    单看bootstrap.handler()这一步很简单,就是把传入一个ChannelHander,然后配置进来

    仔细研究一下传入的这个ChannelInitializer 这是一个很重要的组件

    ChannelInitializer 继承自ChannelHandler,这点毋庸置疑

    首先解释一下handler与channel的关系:

    handler会对传入的数据进行处理,各种各样的handler实现了对数据的各种各样的处理

    这些 handler 会组成一个 pipeline,用于处理 IO 事件

    每个 Channel 内部都有一个 pipeline,pipeline 由多个 handler 组成,handler 之间的顺序是很重要的,因为 IO 事件将按照顺序顺次经过 pipeline 上的 handler,这样每个 handler 可以专注于做一点点小事,由多个 handler 组合来完成一些复杂的逻辑。

     首先,我们看两个重要的概念:Inbound 和 Outbound。在 Netty 中,IO 事件被分为 Inbound 事件和 Outbound 事件。

    比如 connect、write、flush 这些 IO 操作是往外部方向进行的,它们就属于 Outbound 事件。 其他的,诸如 accept、read 这种就属于 Inbound 事件。

    对于 Inbound 操作,按照添加顺序执行每个 Inbound 类型的 handler;而对于 Outbound 操作,是反着来的,从后往前,顺次执行 Outbound 类型的 handler。

    看一下继承关系,总接口ChannelHandler,适配器ChannelHandlerAdapter 最后落实到两个抽象类 ChannelInboundHandlerAdapter   channelOutboundHandlerAdapter  

    刚才说的ChannelInitializer 就是InboundHndler的实现

    至于这个适配器Adapter什么用呢?

    马老师,发生什么事了 .. 原来 是有handler 同时实现了Inbound 和 Outbound,通过Adapter完成的,比如 LoggingHandler 这种既可以用来处理 Inbound 也可以用来处理 Outbound 事件的 handler。

    继续回到代码

    看一下ChannelInitiallzer内部的pipeline 如何初始化的

    这里是直接获取了AbstractChannel的pipeline,

    so 就客户端而言,当NioSocketChannel通过构造方法反射来实例化的时候,调用父类构造器new了一个pipeline  还new了一个unsafe 以后会说

    (至于这里为什么用反射,因为灵活啊,比如我们可以不用NioSocketChannel自己写一个继承 AbstractNioByteChannel的类,当bootstra调用.channel()时候可以将我们自己的类传入,通过反射也会实现相应的功能。)

    重点来了,pipeline的实现,默认DefaultChannelPipeline,  pipeline内部定义了一个channel就是刚才的NioSocketChannel,以后会用到

    这里还定义了两个重要参数 head tail

    熟悉数据结构链表的同学对这个不会不敏感,好像链表的头节点和尾节点

    emmm 还是个双向链表 

    尾节点实例化 传进来刚才的pipeline  这个TailContext还继承了ChannelIncoundHandler  说白了 他就是个handler

    调用父类构造,设置了pipeline

    啥意思呢,head tail 其实就是特殊的handler。它的内部还存了pipeline

    捋一捋,ChannelInitializer内部构造了一个pipeline,pipeline内部构造了两个handler-head和tail,head和tail又将pipeline设置到自己的内部 (禁止套娃???)

    ChannelInitializer,head,tail 都属于handler    也就是hanler内套pipeline内套handler内套pipeline  套娃警告!!

    再看一下head的实现

    head明显比tail要复杂,内部存了一个unsafe  这个unsafe直接用的NioSocketChannel的unsafe  这个unsafe类似于jdk的unsafe类,会调用操作系统层的一些资源

    head同时继承了Inbound和OutBound!!!

    此时此刻pipeline是这个样子地,有一个head 和tail

    马上,很快啊,ChannelInitializer就会辅助自定义的handler加入进来

    至于ChannelInitializer什么时候initChannel()辅助生成完整Pipeline的呢。下篇在讲,耗子尾汁.

    第一篇 源码解析-Netty源码之EventLoopGroup线程池分析

    第二篇    源码解析-Netty源码之Bootstrap创建,初始化Channel,Pipeline,handler

  • 相关阅读:
    MySQL语句创建表、插入数据遇到的问题-20/4/18
    【Navicat】MySQL 8.0.17 数据库报2059错误
    MySQL 8.0.17 版安装 || Windows
    C#--Invoke和BeginInvoke用法和区别
    C#--params关键字
    C#--typeof() 和 GetType()区别
    C#--利用反射编写的SqlHelper类
    C#--反射基础
    C#--LINQ--2--LINQ高级查询
    C#--LINQ--1--初学LINQ基础和查询
  • 原文地址:https://www.cnblogs.com/ttaall/p/14206818.html
Copyright © 2020-2023  润新知