第 8 章

概述

    在前面的章节中,分别对 Netty 的各个核心组件进行了详细的介绍。那么这些组件是如何协同起来一起工作,构建成为一个引用程序的了?答案就在于引导——简单说来,就是对 Netty 提供的各个核心组件进行配置,组合成为一个可以运行的应用程序。

由于应用程序又有 客户端(client)和服务端(server)两种类型,所以 Netty 中提供了服务端引导(ServerBootStrap )和 客户端引导(BootStrap)。

8.1 引导客户端

8.1.1Channel 和 EventLoopGroup 的兼容性

    Netty 传输有 NIO 和 OIO 两种方式,都有相关的 EventLoopGroup 和 Channel 实现。不同传输方式对应的组件不能混用。如下图

    

    如上图列出的组件,我们要么使用 NIO 为前缀的所有组件,要么使用 OIO 为前缀的所有组件,不能混用,否则会抛异常(IllegalStateException)

    注:在调用 BootStrap 的 bind() 或者 connect()方法之前,必须先调用

    group()—— 用于确定处理事件的 EventLoopGroup

    channel()—— 用于确定待使用的通道类型

    handler()—— 用于确定处理具体业务逻辑的 handler 方法

    否则,也会抛出 IllegalStateException 异常。


8.2 引导服务器

    服务的引导和客户端基本类似,主要的区别在于:服务端会创建两个 EventLoopGroup,一个专门用于创建连接,另一个专门用于连接创建好之后与客户端数据通信的处理

    编写 Netty 应用程序有一个一般的准则:尽可能的重用 EventLoop,以减少线程创建所带来的开销(因为每一个 EventLoop 都由一个线程支撑着)

在引导的过程中添加多个 ChannelHandler

    在 Netty 业务程序中,我们的逻辑部分都是在 ChannelHandler 中进行处理的,所以我们在引导客户端或者服务端的时候,有必要添加多个 ChannelHandler。那怎么添加了?Netty 提供了一个 ChannelInitializer 类,这个内容有一个抽象方法 initChannel(Channel ch),你只需实现这个方法,让后通过 ChannelPipeLine 的相关方法添加你需要的 ChannelHandler 即可。类似于下面这样

bootStrap.handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) 
                     throws Exception {
                	 ChannelPipeline cpl = ch.pipeline();
                	 cpl.addLast(new LoggingHandler(LogLevel.INFO));
                	 cpl.addLast(new EchoClientHandler());
                 }
             });

8.2.1 使用 Netty 的 ChannelOption 和 属性

    AttributeMap的作用在于关联组件和某些数据,如跟踪某个 channel 具体是哪个客户(userId)在使用。通过AttrbuteMap就可以把指定用户的 userId 存储到指定的 channel,实现绑定。类似下面这样做

final AttributeKey<Integer> userId = AttributeKey.valueOf("userId");
BootStrap bootStrap = new BootStrap();
...
bootStrap.attr(userId, 123456);//绑定
...
channel.attr(userId)//获取
...

    详细内容可以参考AttributeMap简介

8.3 关闭

    应用程序启动之后,最终的归宿都是会关闭的,就和人的最终归宿都是会进去极乐世界一样的,如何优雅的离去,这是一个值得思考的问题。Netty 为我们提供了一种优雅关闭所有通信的方法:EventLoopGroup.shutdownGracefully(),该方法可以干净的释放所有的资源。优雅退出有如下好处:

  • 尽快的释放NIO线程、句柄等资源;
  • 如果使用flush做批量消息发送,需要将积攒在发送队列中的待发送消息发送完成;
  • 正在write或者read的消息,需要继续处理;
  • 设置在NioEventLoop线程调度器中的定时任务,需要执行或清理。

    详细内容可以参考Netty优雅的关闭

总结

    本章节介绍了 

    Netty 的各个组件如何通过引导协同串联起来,形成一个应用程序。

    Netty 的一个一般原则:尽可能的重用 EventLoop(处理所有的事件、IO流),以减少线程创建所带来的开销,因为每一个EventLoop 都由一个线程支撑着

    AttributeMap,一个特殊的容器,用于存储属于某个组件特有的数据

    shutdownGracefully:优雅的关闭方式

     下一章,将对 Netty 的单元测试进行讲述


    

    

猜你喜欢

转载自blog.csdn.net/yhs1296997148/article/details/80550064
今日推荐