Netty 3 Bootstrap和Channel的生命周期
Bootstrap简介
Bootstrap :引导程序,将ChannelPipeline、ChannelHandler、EventLoop进行整体关联作用。
Bootstrap的结构中。定义了一个抽象父类,两个具体子类。
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel>
implements Cloneable
抽象类定义中,子类型B是父类型的一个类型参数??这样的泛型定义方式有啥好处???
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel>
public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel>
Bootstrap具体分为了两个实现,分别是服务端引导类和客户端引导类。
ServerBootstrap:用于服务端,使用一个ServerChannel来接受客户端的连接并创建出对应的子Channel。
Bootstrap:用于客户端,只需要一个单独的Channel,来与服务端进行数据交互,对应server端的子Channel。
ServerBootstrap实例程序和API
public void start(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(nettyThread);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
// server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码
ch.pipeline().addLast(new HttpResponseEncoder());
// server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new HttpObjectAggregator(nettyLength));
ch.pipeline().addLast(new HttpServerInboundHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
名称
|
描述
|
group | 设置 ServerBootstrap 要用的 EventLoopGroup。这个 EventLoopGroup 将用于 ServerChannel 和被接受的子 Channel 的 I/O 处理 |
channel | 设置将要被实例化的 ServerChannel 类 |
channelFactory | 如果不能通过默认的构造函数 创建Channel,那么可以提供一个ChannelFactory |
localAddress | 指定 ServerChannel 应该绑定到的本地地址。如果没有指定,则将由操作系 统使用一个随机地址。或者,可以通过 bind()方法来指定该 localAddress |
option | 指定要应用到新创建的 ServerChannel 的 ChannelConfig 的 Channel- Option。这些选项将会通过 bind()方法设置到 Channel。在 bind()方法 被调用之后,设置或者改变 ChannelOption 都不会有任何的效果。所支持 的 ChannelOption 取决于所使用的 Channel 类型。参见正在使用的 ChannelConfig 的 API 文档 |
childOption | 指定当子 Channel 被接受时,应用到子 Channel 的 ChannelConfig 的 ChannelOption。所支持的 ChannelOption 取决于所使用的 Channel 的类 型。参见正在使用的 ChannelConfig 的 API 文档 |
attr | 指定ServerChannel上的属性,属性将会通过bind()方法设置给Channel。 在调用 bind()方法之后改变它们将不会有任何的效果 |
childAttr | 将属性设置给已经被接受的子 Channel。接下来的调用将不会有任何的效果 |
handler | 设置被添加到ServerChannel的ChannelPipeline中的ChannelHandler。 更加常用的方法参见childHandler() |
childHandler | 设置将被添加到已被接受的子Channel的ChannelPipeline中的Channel- Handler。handler()方法和 childHandler()方法之间的区别是:前者所 添加的 ChannelHandler 由接受子 Channel 的 ServerChannel 处理,而 childHandler()方法所添加的ChannelHandler将由已被接受的子Channel 处理,其代表一个绑定到远程节点的套接字 |
clone | 克隆一个设置和原始的 ServerBootstrap 相同的 ServerBootstrap |
bind | 绑定 ServerChannel 并且返回一个 ChannelFuture,其将会在绑定操作完 成后收到通知(带着成功或者失败的结果) |
在ServerBootstrap的创建过程中,通过channel()方法设置了需要被实例化ServerChannel类。
ServerChannel代表客户端和服务端之间的连接。不同的协议有对应不同的ServerChannel。可以从ServerChannel子接口中可以看出,对于不同的协议有不同的ServerChannel子接口。我们要使用的NioServerSocketChannel就是TCP协议的。Java nio中的形式使类似的,对于ServerSocketChannel还有对应的SocketChannel。
ServerSocketChannel和SocketChannel可以参考简单Java Nio通信的逻辑。客户端发起SocketChannel的通信,服务端通过ServerSocketChannel获取对应的SocketChannel。下面是普通Java Nio的服务端代码。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(1234));
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
executor.submit(new SocketChannelThread(socketChannel));
}
}
在初始化过程中添加多个ChannelHandler。
在初始化过程中调用handler或者childHandler方法可以用来添加单个ChannelHandler。但是正常使用中,对于一个Channel需要多个Handler处理,如果把所有处理的逻辑都放在一个Handler中会导致一个臃肿的类,并且毫无扩展性可言。
在Netty提供了一个ChannelInboundHandlerAdapter子类,ChannelInitializer。通过这个可以将多个Handler添加到一个ChannelPipeline中。在添加的过程中,需要注意ChannelHandler的添加顺序。将一些数据梳理的Handler放在前面,业务处理的则放在最后。例如Http服务,需要先将Netty的TCP数据封装成对应的HttpRequest之后我们才能方便使用。
在Netty中提供了常用的ChannelHandler,具体参考ChannelHandler中。
childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
// server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码
ch.pipeline().addLast(new HttpResponseEncoder());
// server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new HttpObjectAggregator(nettyLength));
ch.pipeline().addLast(new HttpServerInboundHandler());
}
})
服务端Channel的生命周期
Channel是服务端和客户端用于传输数据的通道,Channel服务维护套接字连接、IO操作等组件。下面以服务端的NioServerSocketChannel 和对应的NioSocketChannel作为例子。
对于TCP,甚至于所有有连接的传输层协议。都可以归纳为以下三个步骤:建立连接、数据传输、关闭连接。在服务的话需要提前监听端口,用于建立连接。
服务端ServerChannel
通过channel方法设定SeverChannel,通过代码可以看到,通过传入的clazz,构造了一个ReflectiveChannelFactory,并将其赋值到this.channelFactory中。用于后续创建ServerChannel的实例。
ServerBootstrap b = new ServerBootstrap();
....
b.channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128)
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
public B channelFactory(ChannelFactory<? extends C> channelFactory) {