对于如何将Netty不同的部分组织起来,成为一个可以实际运行应用程序,Bootstrap就是我们需要的,引导一个应用程序进行配置,并使其运行起来
Bootstrap类
引导类的层次结构包含一个抽象的父类和两个具体的引导子类
不同的引导类分别作为服务器和客户端的引导,支持不同的应用程序的功能
服务器使用一个父Channel来接受客户端的连接,创建子Channel用于通信
客户端只需要一个单独的,没有父Channel的Channel进行所有网络通信
首先是Bootstrap类开始
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
子类型B方便返回运行时实例的引用
子类的声明如下
public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
引导Bootstrap中有很多API,继承了AbstractBootstrap类
我们进行客户端的引导过程
Bootstrap类为客户端和应用程序创建Channel
Channel和EventLoopGroup的兼容性
对于NIO和OIO传输两者来说,都有不同的EventLoopGroup和Channel的实现
如果将NIO和OIO的EventLoop和Channel混合起来了的话,会可能出现问题,尤其是出现IllegalStateException
创建了一个Bootstrap的实例,绑定了NIO的EventLoopGroup的实现,
Channel指定的却是OIO的Channel实现类
会导致IllegalStateException,混用了不兼容的传输
在引导过程中,调用bind()或者 connect()方法之前,调用以下方法来设置所需的组件
group()
channel或者channelFactory()
handler()
不然就导致IllegalStateException
服务器端的引导是我们需要主要深究的方向
serverBootstrap的api如下
从上面的API列表中可以看出,Server端的引导器比起客户端的多了不少方法,比如childHandler
ChildAttr childOption,因为Server端的引导,是由一个ServerChannel负责创建子Channel
子Channel代表了已经被接受的连接,因此,负责引导ServerChannel的ServerBootstrap提供了这些方法
下面就是ServerBootstrap的bind()方法在调用的时候创建了一个ServerChannel,并且这个ServerChannel管理了多个子Channel
整体的ServerBootstrap的引导流程如下
假如,我们需要处理一个客户端的请求,然后把自己作为客户端,将这个请求转发出去,那么需要在已经接受的子Channel中引导一个客户端Channel
通过已经被接受的子Channel的EventLoop传递给Bootstrap的group()方法来共享这个EventLoop,这就避免了额外的线程创建
ServerChannel创建的Channel再去引导一个Bootstrap,并且利用一个EventLoop来进行线程的共享,避免了上下文的切换
上面说了,尽可能使用EventLoop来避免线程上下文切换带来的开销
如何在引导的过程中添加多个ChannelHandler呢?
如果我们需要多个Handler利用一个ChannelPipeline进行串联的话,我们如何做呢?
Netty是有一个特殊的ChannelInboundHandlerAdapter子类
定义了如下的方法
在传入Bootstrap之后,一旦Channel注册到了EventLoop之后,会调用这个InitChannel方法,在这个方法中,我们可以利用传入的Channel获得对应的ChannelPipeline
然后添加对应的Handler
基本代码如下
设置Netty的ChannelOption和属性
每个Channel创建时候都手动配置会导致相当的麻烦,所以可以在引导的时候配置一个ChannelOption,然后自动为所有的Channel进行加上这个配置
ChannelOption 包括底层连接的详情,如keep-alive和缓冲区设置
Netty甚至提供了AttributeMap抽象 有Channel和引导类提供的集合
和AttributeKey, 插入和获取属性值的泛型类
使用这个工具,将Channel和其他类型的数据绑定
比如,将用户Id和Channel绑定
具体的使用ChannelOption的方式如下
对于基于无连接的协议的SocketChannel,Netty提供了各类DatagramChannel的实现
对于引导启动的关闭
需要我们在JVM退出的时候处理好一切
我们需要关闭EventLoopGroup,处理任何挂起的事件和任务,然后释放所有的线程,这就是调用EventLoopGroup.shutdownGracefully()方法的作用,返回调用一个Future,这说明这个方法是异步的,需要我们阻塞等待响应,或者注册一个监听器在关闭完成时候获得通知