这是我参与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的线程模型。
结尾
我是一个正在被打击还在努力前进的码农。如果文章对你有帮助,记得点赞、关注哟,谢谢!
本文转载自: 掘金