6.1 客户端 BootStrap

6.1.1 Channel 简介
在 Netty 中,Channel 是一个 Socket 的抽象,它为用户提供了关于 Socket 状态(是否是连接还是断开)以及对 Socket
的读写等操作。每当 Netty 建立了一个连接后, 都创建一个对应的 Channel 实例。
除了 TCP 协议以外,Netty 还支持很多其他的连接协议, 并且每种协议还有 NIO(非阻塞 IO)和 OIO(Old-IO, 即传统的
阻塞 IO)版本的区别。不同协议不同的阻塞类型的连接都有不同的 Channel 类型与之对应下面是一些常用的 Channel
类型:

6.1.2 NioSocketChannel 的创建
Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化。
下面我先来看一个例子, 从客户端和服务器端分别分析一下 Netty 的程序是如何启动的。首先,让我们从客户端的代码
片段开始: 
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//自定义协议解码器
/** 入参有5个,分别解释如下
maxFrameLength:框架的最大长度。如果帧的长度大于此值,则将抛出TooLongFrameException。
lengthFieldOffset:长度字段的偏移量:即对应的长度字段在整个消息数据中得位置
lengthFieldLength:长度字段的长度:如:长度字段是int型表示,那么这个值就是4(long型就是8)
lengthAdjustment:要添加到长度字段值的补偿值
initialBytesToStrip:从解码帧中去除的第一个字节数
*/
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
//自定义协议编码器
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
//对象参数类型编码器
pipeline.addLast("encoder", new ObjectEncoder());
//对象参数类型解码器
pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
pipeline.addLast("handler",consumerHandler);
}
}); ChannelFuture future = b.connect("localhost", 8080).sync();
future.channel().writeAndFlush(msg).sync();
future.channel().closeFuture().sync();
} catch(Exception e){
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
从上面的客户端代码虽然简单, 但是却展示了 Netty 客户端初始化时所需的所有内容:
1、EventLoopGroup:不论是服务器端还是客户端, 都必须指定 EventLoopGroup。在这个例子中, 指定了
NioEventLoopGroup, 表示一个 NIO 的 EventLoopGroup。
2、ChannelType: 指定 Channel 的类型。 因为是客户端,因此使用了 NioSocketChannel。
3、Handler: 设置处理数据的 Handler。
下面我们继续深入代码,看一下客户端通过 Bootstrap 启动后,都做了哪些工作?我们看一下 NioSocketChannel 的
类层次结构如下:
 

回到我们在客户端连接代码的初始化 Bootstrap 中调用了一个 channel()方法,传入的参数是 NioSocketChannel.class,
在这个方法中其实就是初始化了一个 ReflectiveChannelFactory 的对象:
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
而 ReflectiveChannelFactory 实现了 ChannelFactory 接口, 它提供了唯一的方法, 即 newChannel()方法,
ChannelFactory, 顾名思义, 就是创建 Channel 的工厂类。进入到 ReflectiveChannelFactory 的 newChannel()方法中,
我们看到其实现代码如下: 
public T newChannel() {
// 删除了 try...catch 块
return clazz.newInstance();
}
根据上面代码的提示,我们就可以得出:
1、Bootstrap 中的 ChannelFactory 实现类是 ReflectiveChannelFactory。
2、通过 channel()方法创建的 Channel 具体类型是 NioSocketChannel。
Channel 的实例化过程其实就是调用 ChannelFactory 的 newChannel()方法,而实例化的 Channel 具体类型又是和初
始化 Bootstrap 时传入的 channel()方法的参数相关。因此对于客户端的 Bootstrap 而言,创建的 Channel 实例就是
NioSocketChannel。 
 
6.1.3 客户端 Channel 的初始化
前面我们已经知道了如何设置一个 Channel 的类型,并且了解到 Channel 是通过 ChannelFactory 的 newChannel()方
法来实例化的, 那么 ChannelFactory 的 newChannel()方法在哪里调用呢?继续跟踪, 我们发现其调用链如下:

在 AbstractBootstrap 的 initAndRegister()中调用了 ChannelFactory()的 newChannel()来创建一个 NioSocketChannel
的实例,其源码如下:
final ChannelFuture initAndRegister() {
Channel channel = null; try {
channel = this.channelFactory.newChannel();
this.init(channel);
} catch (Throwable var3) {
if (channel != null) {
channel.unsafe().closeForcibly();
return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
} return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
} ChannelFuture regFuture = this.config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
} return regFuture;
}
在 newChannel()方法中,利用反射机制调用类对象的 newInstance()方法来创建一个新的 Channel 实例,相当于调用
NioSocketChannel 的默认构造器。NioSocketChannel 的默认构造器代码如下: 

Netty(六)揭开 BootStrap 的神秘面纱的更多相关文章

  1. Netty之揭开BootStrap 的神秘面纱

    客户端BootStrap: Bootstrap 是Netty 提供的一个便利的工厂类, 我们可以通过它来完成Netty 的客户端或服务器端的Netty 初始化.下面我先来看一个例子, 从客户端和服务器 ...

  2. ASP.NET 运行时详解 揭开请求过程神秘面纱

    对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就 ...

  3. 带你揭开ATM的神秘面纱

    相信大家都用过ATM取过money吧,但是有多少人真正是了解ATM的呢?相信除了ATM从业者外了解的人寥寥无几吧,鄙人作为一个从事ATM软件开发的伪专业人士就站在我的角度为大家揭开ATM的神秘面纱吧. ...

  4. 揭开Future的神秘面纱——结果获取

    前言 在前面的两篇博文中,已经介绍利用FutureTask任务的执行流程,以及利用其实现的cancel方法取消任务的情况.本篇就来介绍下,线程任务的结果获取. 系列目录 揭开Future的神秘面纱—— ...

  5. 揭开Future的神秘面纱——任务执行

    前言 此文承接之前的博文 解开Future的神秘面纱之取消任务 补充一些任务执行的一些细节,并从全局介绍程序的运行情况. 系列目录 揭开Future的神秘面纱——任务取消 揭开Future的神秘面纱— ...

  6. 揭开Future的神秘面纱——任务取消

    系列目录: 揭开Future的神秘面纱——任务取消 揭开Future的神秘面纱——任务执行 揭开Future的神秘面纱——结果获取 使用案例 在之前写过的一篇随笔中已经提到了Future的应用场景和特 ...

  7. SparkSQL大数据实战:揭开Join的神秘面纱

    本文来自 网易云社区 . Join操作是数据库和大数据计算中的高级特性,大多数场景都需要进行复杂的Join操作,本文从原理层面介绍了SparkSQL支持的常见Join算法及其适用场景. Join背景介 ...

  8. 揭开HTTPS的神秘面纱

    摘自:https://www.cnblogs.com/hujingnb/p/11789728.html 揭开HTTPS的神秘面纱   在说HTTP前,一定要先介绍一下HTTP,这家伙应该不用过多说明了 ...

  9. 揭开Docker的神秘面纱

    Docker 相信在飞速发展的今天已经越来越火,它已成为如今各大企业都争相使用的技术.那么Docker 是什么呢?为什么这么多人开始使用Docker? 本节课我们将一起解开Docker的神秘面纱. 本 ...

随机推荐

  1. DC-DC变换器,24v转5v稳压芯片,3A输出电流

    在24V输入中,比较合适的LDO可以选择:PW6206,输出电压3V,3.3V,5V 输入电压最高40V,功耗也低4uA左右,采用SOT23-3封装. PW6206系列是一个高精度,高输入电压低静态电 ...

  2. 消息队列之activeMQ

    1.activeMQ的主要功能 实现高可用.高伸缩.高性能.易用和安全的企业级面向消息服务的系统 异步消息的消费和处理 控制消息的消费顺序 可以和Spring/springBoot整合简化编码 配置集 ...

  3. 都知道Base64,Base32你能实现吗?

    很长时间没有更新个人博客了,因为前一段时间在换工作,入职了一家新的公司,刚开始需要适应一下新公司的节奏,开始阶段也比较忙.新公司还是有一定的技术气氛的,每周都会有技术分享,而且还会给大家留一些思考题, ...

  4. 每月一更的《HelloGitHub》第 58 期,来啦!

    HelloGitHub 分享 GitHub 上有趣.入门级的开源项目.欢迎大家: 贡献代码 宣传你觉得优秀的项目 Star 项目️ 本月刊是每月 28 号更新,再见月刊就是年后了.在这里提前祝大家:新 ...

  5. 在原生开发中控制HTML5视频!

    在原生开发中控制HTML5视频! PC端 视频如何自动播放! 在video标签中添加 autoplay + muted(静音属性!) 温馨提醒: video是一个块级元素! 但是唯一的缺陷就是视频没有 ...

  6. H3C防火墙开启区域间互访

    配置ip和路由以及将端口放至Untrust之后,外网还是不通,需要以下命令 interzone policy default by-priority 或者下面: security-zone intra ...

  7. Linux 通过端口终止进程

    以下命令可用于杀死占用某端口的所有进程. root 用户: kill -9 $(lsof -i tcp:进程号 -t) 非 root 用户: kill -9 $(sudo lsof -i tcp:进程 ...

  8. 宝塔Linux命令

    安装宝塔 Centos安装脚本 5.7:yum install -y wget && wget -O install.sh http://download.bt.cn/install/ ...

  9. Prometheus-process exporter-进程监控

    Prometheus-process exporter-进程监控 1.下载安装 2.修改配置文件 3.启动 相关内容原文地址: 博客园:落烨无痕:process exporter 配置项解释 huan ...

  10. Form表单的知识点汇总

    分享学习到的Form知识点,希望给同样有所需要的朋友共同学习..愿我的分享,可以成为您的厚爱.. 简单的知识收到简单的回报,未来的努力造就优秀的自己... <!--<form> -- ...