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. 入门OJ:郭嘉的消息传递

    题目描述 我们的郭嘉大大在曹操这过得逍遥自在,但是有一天曹操给了他一个任务,在建邺城内有N(<=1000)个袁绍的奸细 将他们从1到N进行编号,同时他们之间存在一种传递关系,即若C[i,j]=1 ...

  2. 入门OJ:八中生成树2

    题目描述 八中里面有N个建设物,M条边.对于这种要建最小生成树的问题,你应该很熟练了.现在老大决定降低某条边的费用,然后这条边必须要被选中,因为这条路他每天都要走,自然......问选了这条边后是否可 ...

  3. MongoDB 总结

    目录 1. 逻辑结构 2. 安装部署 2.1 系统准备 2.2 mongodb安装 2.2.1 创建所需用户和组 2.2.2 创建mongodb所需目录结构 2.2.3 上传并解压软件到指定位置 2. ...

  4. 配置HDFS的HA

    配置前准备: -- 配置hadoop -- 配置ZooKeeper,传送门:https://www.cnblogs.com/zhqin/p/11906106.html 安装配置好hadoop和ZooK ...

  5. https://dev.mysql.com/doc/refman/8.0/en/savepoint.html

    https://dev.mysql.com/doc/refman/8.0/en/savepoint.html

  6. 监听套接字描述字 已连接套接字描述字 和打电话的情形非常不一样的地方 完成了 TCP 三次握手,操作系统内核就为这个客户生成一个已连接套接字

    1. accept: 电话铃响起了-- 当客户端的连接请求到达时,服务器端应答成功,连接建立,这个时候操作系统内核需要把这个事件通知到应用程序,并让应用程序感知到这个连接.这个过程,就好比电信运营商完 ...

  7. POJ2961_kmp

    Period Time Limit: 3000MS   Memory Limit: 30000KB   64bit IO Format: %I64d & %I64u Submit Status ...

  8. python中字符串的翻转(方法总结)

    Python翻转字符串(reverse string), 一共包含5种方法, 其中第一种最简单, 即步长为-1, 输出字符串; 方法如下 5种方法的比较: 1. 简单的步长为-1, 即字符串的翻转(常 ...

  9. 通过模拟数据,使用js在前端实现模糊查询下拉框功能实例教程

    所谓模糊查询就是通过关键字在数据中匹配到包含关键字的数据,而得出的查询结果.本实例教程讲解在前端文本框输入关键字,显示匹配的数据列表功能. 首先得准备一个文本框和显示数据列表的div元素,html代码 ...

  10. 【bzoj 3232】圈地游戏(算法效率--01分数规划+图论--最小割)

    题目:DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用.DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走 ...