這篇講netty服務端ServerBootstrap如何啟動
前言
BootStrap在netty的應用程式中負責引導伺服器和客戶端。netty包含了兩種不同型別的引導:
- 使用伺服器的ServerBootStrap,用於接受客戶端的連線以及為已接受的連線建立子通道。
- 用於客戶端的BootStrap,不接受新的連線,並且是在父通道類完成一些操作。
一般服務端的程式碼如下所示:
public final class SimpleServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new SimpleServerHandler())
.childHandler(new SimpleServerInitializer())
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
private static class SimpleServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelRegistered");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerAdded");
}
}
public class SimpleServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:" + ch.remoteAddress()+"連線上");
}
}
在上篇博文(插入上篇文章)中 剖析瞭如下的兩行程式碼內部的建構函式中幹了些什麼。
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap如何啟動
本篇文章將分析如下幾行程式碼裡面做了些什麼。
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new SimpleServerHandler())
.childHandler(new SimpleServerInitializer())
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
我們看下建構函式將workerGroup儲存在 ServerBootstrap物件的childGroup屬性上。 bossGroup儲存在ServerBootstrap物件的group屬性上
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
if (childGroup == null) {
throw new NullPointerException("childGroup");
}
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}
設定父類屬性channelFactory 為: BootstrapChannelFactory類的物件。其中這裡BootstrapChannelFactory物件中包括一個class屬性為:NioServerSocketChannel.class,從如下該類的建構函式中可以明顯的得到這一點。
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new BootstrapChannelFactory<C>(channelClass));
}
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
if (channelFactory == null) {
throw new NullPointerException("channelFactory");
}
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
this.channelFactory = channelFactory;
return (B) this;
}
並且BootstrapChannelFactory中提供 newChannel()方法,我們可以看到 clazz.newInstance(),主要是通過反射來例項化NioServerSocketChannel.class
rivate static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Class<? extends T> clazz;
BootstrapChannelFactory(Class<? extends T> clazz) {
this.clazz = clazz;
}
@Override
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
@Override
public String toString() {
return StringUtil.simpleClassName(clazz) + ".class";
}
}
這裡的handler函式的入參類是我們自己提供的。如下,後面的博文中將會分析這個handler將會在哪裡以及何時被呼叫,這裡只需要記住這一點即可
public B handler(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
return (B) this;
}
由最後一句可知,其實就是講傳入的childHandler賦值給ServerBootstrap的childHandler屬性。
該函式的主要作用是設定channelHandler來處理客戶端的請求的channel的IO。 這裡我們一般都用ChannelInitializer這個類的例項或則繼承自這個類的例項
這裡我是通過新建類SimpleChatServerInitializer繼承自ChannelInitializer。具體的程式碼如下
public ServerBootstrap childHandler(ChannelHandler childHandler) {
if (childHandler == null) {
throw new NullPointerException("childHandler");
}
this.childHandler = childHandler;
return this;
}
由最後一句可知,其實就是講傳入的childHandler賦值給ServerBootstrap的childHandler屬性。
該函式的主要作用是設定channelHandler來處理客戶端的請求的channel的IO。 這裡我們一般都用ChannelInitializer這個類的例項或則繼承自這個類的例項
這裡我是通過新建類SimpleChatServerInitializer繼承自ChannelInitializer。具體的程式碼如下:
public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:" + ch.remoteAddress()+"連線上");
}
}
我們再看看ChannelInitializer這個類的繼承圖可知ChannelInitializer其實就是繼承自ChannelHandler的
可知,這個類其實就是往pipeline中添加了很多的channelHandler。
ServerBootstrap的option
這裡呼叫的是父類的AbstractBootstrap的option()方法,原始碼如下:
public <T> B option(ChannelOption<T> option, T value) {
if (option == null) {
throw new NullPointerException("option");
}
if (value == null) {
synchronized (options) {
options.remove(option);
}
} else {
synchronized (options) {
options.put(option, value);
}
}
return (B) this;
}
其中最重要的一行程式碼就是:
options.put(option, value);
這裡用到了options這個引數,在AbstractBootstrap的定義如下:
private final Map<ChannelOption, Object> options = new LinkedHashMap, Object>();
可知是私有變數,而且是一個Map集合。這個變數主要是設定TCP連線中的一些可選項,而且這些屬性是作用於每一個連線到伺服器被建立的channel。
ServerBootstrap的childOption
這裡呼叫的是父類的ServerBootstrap的childOption()方法,原始碼如下:
public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
if (childOption == null) {
throw new NullPointerException("childOption");
}
if (value == null) {
synchronized (childOptions) {
childOptions.remove(childOption);
}
} else {
synchronized (childOptions) {
childOptions.put(childOption, value);
}
}
return this;
}
這個函式功能與option()函式幾乎一樣,唯一的區別是該屬性設定只作用於被acceptor(也就是boss EventLoopGroup)接收之後的channel。到此為止netty的初始化設定完成,下篇文章我們講一下啟動過程。
結束
結束
識別下方二維碼!回覆:
入群
,掃碼加入我們交流群!