Java后端开发-Netty学习笔记

1. Netty介绍

Netty是高性能的、异步、事件驱动的NIO框架,基于java nio提供的api实现。

2. 源码分析

2.1. 基本组件

2.1.1. NioEventLoop

Netty最核心的就是Reactor线程,对应NioEventLoop。
  • Reactor模式介绍:
    参考:
    https://tech.youzan.com/yi-bu-wang-luo-mo-xing/
    https://www.jianshu.com/p/2965fca6bb8f
  • Reactor角色构成:
  1. Handle(句柄或描述符):本质上表示一种资源,是由操作系统提供的;该资源用于表示一个个的事件,比如说文件描述符,或是针对网络编程中的Socket描述符。事件既可以来自外部,也可以来自内部;外部事件比如说客户端的连接请求,客户端发过来的数据等;内部事件比如说操作系统产生的定时器事件等。它本质上是一个文件描述符。Handle是事件发源地。
  2. Syncronous Event Demutiplexer(同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件发生为止,对于linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等,在java nio领域中,同步事件分离器对应的组件就是selector;对应的阻塞方法就是select方法。
  3. Event Handler(事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制。Netty相比于java nio 来说在事件处理器这个角色上进行了升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理。
  4. Concrete Event Handler(具体时间处理器):是事件处理器的实现。它本身实现了事件处理器所提供的各个回调方法,从而实现了特定的业务逻辑。它本质上是我们所编写的一个个的处理器实现。
  5. Initiation Dispatcher(初始分发器):实际上就是Reactor角色,它本身 定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理的注册、删除等设施。它本身是整个事件处理器的核心所在,Initiation Dispatcher 会通过同步事件分离器来等待事件的发生,一旦事件发生,Initation Dispatcher 首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理。

2.1.2. Channel

以Netty常见的Socket编程中的服务端程序启动流程,分析服务端Channel的创建、初始化、以及注册到Selector过程。
  • 服务端启动流程
  1. 创建服务端Channell
  • bind()[用户代码入口]
  • initAndRegister()[初始化并注册]
  • newChannel()[创建服务端Channel]
    反射创建服务端Channel,在NioServerSocketChannel构造方法中:
    1.new Socket()[创建jdk底层的Channel]
    2.NioServerSocketChannelConfig()[tcp参数配置类]
    3.AbstractNioChannel()
    configureBlocking(false)[阻塞模式:设置服务端Channel为非阻塞]
    AbstractChannel()[创建id(Channel的唯一标识)、unsafe(jdk channel底层TCP读写数据用)、pipline(服务端或客户端的业务逻辑链)]
  1. 初始化服务端Channel
  • bind()[用户代码入口]
  • initAndRegister()[初始化并注册]
  • newChannel()[创建服务端Channel](见1.创建服务端Channel)
  • init()[初始化入口]
  • set ChannelOptions, ChannelAttrs(遍历ServerBootstrap中配置的option和attr,来配置bossGroup的options和attrs)
  • set ChildOptions, ChildAttrs(遍历ServerBootstrap中配置的childOption和childAttr,来配置workerGroup的options和attrs)
  • config hadler [配置服务端pipline]
  • add ServerBootstrapAcceptor [添加连接器(特殊的hadler)]
  1. 注册Selector

  2. 端口绑定

2.1.3. ChannelHandler

2.1.4. Pipline

2.1.5. ByteBuf

2.2. 重要结论

1. 一个EventLoopGroup中包含一个或多个EventLoop。
2. 一个EventLoop在它整个生命周期当中只会与唯一一个Thread进行绑定。
3. 所有由EventLoop所处理的各种I/O事件,都将在它所关联的那个Thread上进行处理。
4. 一个Channel在整个生命周期中只会注册在一个EventLoop上。
5. 一个EventLoop在运行当中,会被分配一个或多个Channel。

重要结论1:
在Netty当中Channel的实现一定是线程安全的;基于此,我们可以存储一个Channel的引用,并且在需要往远程断点发送数据时,通过这个引用来调用Channel 相关的方法;即便当时有很多的线程都在使用它也不会出现多线程安全问题;而且消息一定会被按顺序发送出去。

重要结论2:
在业务开发中,不要将耗时任务放入到EventLoop的执行队列当中,因为它会一直阻塞该线程所对应的所有其他任务,如果我们进行阻塞调用或者耗时操作,那么就需要使用一个专门的EventExecutor(业务线程池)。
通常会有两种实现方式:
1.在ChannelHandler的回调方法中,使用自己定义的业务线程池,实现异步调用、
2.借助Netty提供的向ChannelPipline增加ChannelHandler时调用的addLast方法来传递	  EventExecutor。
说明:默认情况下,即调用addLast(ChannelHandler... handler),ChannelHandler中的回调方法都是由I/O线程所执行,如果调用addLast(EventExecutorGroup group, ChannelHandler... handler) 方法,那么ChannelHandler中的回调方法是由参数中的group线程组来执行的。
发布了7 篇原创文章 · 获赞 5 · 访问量 92

猜你喜欢

转载自blog.csdn.net/weixin_41085114/article/details/99479616
今日推荐