这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
前言
今天是七夕,首先祝大家七夕快乐吧。废话不多说,进入正题。
程序引导类(Bootstrap)可以理解为是一个程序的入口程序,在 Java 程序中,就是一个包含 main 方法的程序类。在 Netty 中,引导程序还包含一系列的配置项。本篇文章我们就来介绍 Netty 的引导程序。
引导程序类
引导程序类是一种引导程序,使 Netty 程序可以很容易地引导一个 Channel。在 Netty 中,承担引导程序的是 AbstractBootStrap
抽象类。
引导程序类都在io.netty.bootstrap
包下。AbstractBootStrap
抽象类有两个子类:Bootstrap
和ServerBootstrap
,分别用于引导客户端程序及服务的程序。
下图展示了引导程序类的关系:
AbstractBootStrap 抽象类
从上图可以看出,AbstractBootStrap
抽象类实现了Cloneable
接口。那么为什么需要实现Cloneable
接口呢?
在 Netty 中经常需要创建多个具有类似配置或者完全相同配置的Channel
。为了支持这种模式而又不避免为每个Channel
都创建并配置一个新的引导类实例,因此AbstractBootStrap
被标记为了Cloneable
。在一个已经配置完成的引导实例上调用clone()
方法将返回另一个可以立即使用的引导类实例。
这种方式只会创建引导类实例的EventLoopGroup
的一个浅拷贝,所以,EventLoopGroup
将在所有克隆的Channel
实例之间共享。这是可以接受的,毕竟这些克隆的Channel
的生命周期都很短暂,例如,一个典型的场景是创建一个Channel
以进行一次HTTP
请求。
以下是AbstractBootStrap
的核心源码:
1 | java复制代码public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable { |
从上述源码可以看出,子类型B是其父类型的一个类型参数,因此可以返回到运行时实例的引用以支持方法的链式调用。从私有变量可以看出,AbstractBootStrap
所要管理的启动配置包括EventLoopGroup
、SocketAddress
、Channel配置
、ChannelHandler
等信息。
AbstractBootStrap
是禁止被除io.netty.bootstrap
包外其他程序所扩展的,因此可以看到AbstractBootStrap
默认构造方法被设置为了包内可见。
Bootstrap 类
BootStrap 类是AbstractBootStrap
抽象类的子类之一,主要是用于客户端或者使用了无连接协议的应用程序。
以下是BootStrap
类的核心源码:
1 | java复制代码public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> { |
上述方法主要分为以下几类:
- group:设置用于处理
Channel
所有事件的EventLoopGroup
。 - channel:指定了
Channel
的实现类。 - localAddress:指定
Channel
应该绑定到的本地地址。如果没有指定,则有操作系统创建一个随机的地址。或者,也可以通过bind()
或者connect()
方法指定localAddress
。 - option:设置
ChannelOption
,其将被应用到每个新创建的Channel
的ChannelConfig
。这些选项将会通过bind()
或者connect()
方法设置到Channel
,配置的顺序与调用先后没有关系。这个方法在Channel
已经被创建后再次调用就不会再起任何效果了。支持什么样的ChannelOption
取决于所使用的Channel
类型。 - attr:指定新创建的
Channel
的属性值。这些属性值是通过bind()
或者connect()
方法设置到Channel
。配置的顺序取决于调用的先后顺序。这个方法在Channel
已经被创建后再次调用就不会再起任何效果了。 - handler:设置被添加到
ChannelPipeline
以接收事件通知的ChannelHandler
。 - remoteAddress:设置远程地址。也可以通过
connect()
方法来指定它。 - clone:创建一个当前
Bootstrap
的克隆,其具有和原始的Bootstrap
相同的设置信息。 - connect:用于连接到远程节点并返回一个
ChannelFuture
,并将会在连接操作完成后接收到通知。 - bind:绑定
Channel
并返回一个ChannelFuture
,其将会在绑定操作完成之后接收到通知,在那之后必须调用Channel
。
BootStrap
类中许多方法都继承自AbstractBootstrap
类。
ServerBootstrap 类
ServerBootstrap 类是AbstractBootStrap
抽象类的子类之一,主要是用于引导服务器程序。
以下是 ServerBootstrap 类的源码:
1 | java复制代码public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> { |
上述方法主要分为以下几类:
- group:设置
ServerBootstrap
要用的EventLoopGroup
。这个EventLoopGroup
将用于ServerChannel
和被接受的子Channel
的 I/O 处理。 - channel:设置将要被实例化的
ServerChannel
类。 - localAddress:指定
ServerChannel
应该绑定到的本地地址。如果没有指定,则有操作系统创建一个随机的地址。或者,也可以通过bind()
方法指定localAddress
。 - option:指定要应用到新创建的
ServerChannel
的ChannelConfig
的ChannelOption
。这些选项将会通过bind()
设置到Channel
,在bind()
方法被调用之后,设置或者改变ChannelOption
将不会有任何效果。支持什么样的ChannelOption
取决于所使用的Channel
类型。 - childOption:指定当子
Channel
被接受时,应用到子Channel
的ChannelConfig
的ChannelOption
。所支持的ChannelOption
取决于所使用的Channel
类型。 - attr:指定
ServerChannel
上的属性值。这些属性值是通过bind()
或者connect()
方法设置到Channel
。在bind()
方法被调用之后它们将不会有任何效果。 - childAttr:将属性设置给已经被接受的子
Channel
。之后再次调用将不会有任何效果。 - handler:设置被添加到
ServerChannel
的ChannelPipeline
中的ChannelHandler
。 - childHandler:设置将被添加到已被接受的子
Channel
的ChannelPipeline
中的ChannelHandler
。 - clone:克隆一个设置好原始的
ServerBootstrap
相同的ServerBootstrap
。 - bind:绑定
ServerChannel
并返回一个ChannelFuture
,其将会在绑定操作完成之后接收到通知(带着成功或者失败的结果)。
ServerBootstrap
类中许多方法都继承自AbstractBootstrap
类。
引导服务器
为了能更好的理解引导程序,下面就以 Echo 协议的服务器的代码为例。核心代码如下:
1 | java复制代码// 多线程事件循环器 |
引导 Netty 服务器主要分为几下几个步骤。
1、实例化引导程序类
在上述代码中,首先是需要实例化引导程序类。由于是服务器端的程序,所以,实例化了一个ServerBootstrap
。
2、设置 EventLoopGroup
设置ServerBootstrap
的EventLoopGroup
。上述服务器使用了两个NioEventLoopGroup
,一个代表boss
线程组,一个代表work
线程组。
boss
线程主要是接收客户端的请求,并将请求转发给work
线程处理。
boss
线程是轻量的,不会处理耗时的任务,因此可以承受高并发的请求。而真实的 I/O 操作都是由work
线程在执行。
NioEventLoopGroup
是支持多线程的,因此可以执行线程池的大小。如果没有指定,则 Netty 会指定一个默认的线程池大小,核心代码如下:
1 | java复制代码 private static final int DEFAULT_EVENT_LOOP_THREADS; |
从上述源码可以看出,如果NioEventLoopGroup
实例化时,没有指定线程数,则最终默认值是DEFAULT_EVENT_LOOP_THREADS
,而默认值DEFAULT_EVENT_LOOP_THREADS
是根据当前机子的CPU 处理的个数乘以 2 得出的。
3、指定 Channel 类型
channel()
方法用于指定ServerBootstrap
的Channel
类型。在本例中,使用的是NioServerSocketChannel
类型,代表了服务器是一个基于ServerSocketChannel
的实现,使用基于 NIO 选择器的实现来接受新连接。
4、指定 ChannelHandler
childHandler
用于指定ChannelHandler
,以便处理Channel
的请求。上述例子中,指定的是自定义的EchoServerHandler
。
5、设置 Channel 选项
option
和childOption
方法,分别用于设置ServerChannel
及ServerChannel
的子Channel
的选项。这些选项定义在ChannelOption
类中,包含以下常量:
1 | java复制代码public class ChannelOption<T> extends AbstractConstant<ChannelOption<T>> { |
6、绑定端口启动服务
bind()
方法用于绑定端口,会创建一个Channel
而后启动服务。
绑定成功后,返回一个ChannelFuture
,以代表是一个异步的操作。在上述的例子里,使用的是sync()
方法,以同步的方式来获取服务启动的结果。
引导客户端
为了能更好的理解引导程序,下面就以 Echo 协议的客户端的代码为例。核心代码如下:
1 | java复制代码// 配置客户端 |
引导 Netty 客户端主要分为几下几个步骤。
1、实例化引导程序类
在上述代码中,首先是需要实例化引导程序类。由于是客户端的程序,所以,实例化了一个Bootstrap
。
2、设置 EventLoopGroup
设置Bootstrap
的EventLoopGroup
。不同于服务器,客户端只需要使用了一个NioEventLoopGroup
。
3、指定 Channel 类型
channel()
方法用于指定Bootstrap
的Channel
类型。在本例中,由于是客户端使用,使用的是NioSocketChannel
类型,代表了客户端是一个基于SocketChannel
的实现,使用基于 NIO 选择器的实现来发起连接请求。
4、设置 Channel 选项
option
用于设置Channel
的选项。这些选项定义在ChannelOption
类中。
5、指定 ChannelHandler
Handler
用于设置处理服务端请求的ChannelHandler
。上述例子中,指定的是自定义的EchoClientHandler
。
6、连接到服务器
connect()
方法用于连接到指定的服务器的Channel
。
连接成功后,返回一个ChannelFuture
,以代表是一个异步的操作。在上述的例子里,使用的是sync()
方法,以同步的方式来获取服务启动的结果。
总结
通过上述对引导程序类的介绍,相信大家对于服务端和客户端的引导程序以及一些配置项的都有了一定的了解。通过看源码,我们就能更加清楚的知道 Netty 服务端和客户端的启动的过程。下节我们来分析Netty的线程模型。
结尾
我是一个正在被打击还在努力前进的码农。如果文章对你有帮助,记得点赞、关注哟,谢谢!
本文转载自: 掘金