Netty(4)初步瞭解 Netty服務端初始化過程
我們看Netty服務端初始化大致做了什麼
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new MyServerInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
ServerBootstrap
ServerBootstrap負責初始化netty伺服器,並且開始監聽埠的socket請求。
1. 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;
}
parentGroup
就是bossGroup,childGroup
就是workerGroup
super.group(parentGroup);
呼叫的是父類AbstractBootstrap#group()
方法
public B group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return (B) this;
}
做了些基本的判斷,並且返回 (B)this。實際上,AbstractBootstrap 整個方法的呼叫,基本都是“鏈式呼叫”。
2. channel
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
-
io.netty.channel.ReflectiveChannelFactory
會將傳入的channelClass(在這這裡也就是NioServerSocketChannel.class
)進行封裝
public ReflectiveChannelFactory(Class<? extends T> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
this.clazz = clazz;
}
- 呼叫
channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory)
方法,設定channelFactory
屬性。
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
return channelFactory((ChannelFactory<C>) channelFactory);
}
io.netty.channel.ChannelFactory
,Channel 工廠介面,用於建立 Channel 物件。NioServerSocketChannel.class
就意味著之後建立的channel都是非阻塞。
3. childHandler childHandler
這裡主要就是定義後續每條連線的資料讀寫,業務處理邏輯,後面解析。
4. bind
bind()是非常核心的方法,之前的ServerBootstrap所做的事情都是為bind()做準備。bind() 方法,繫結埠,啟動服務端。
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
// 校驗服務啟動需要的必要引數
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
// 繫結本地地址( 包括埠 )
return doBind(localAddress);
}
private ChannelFuture doBind(final SocketAddress localAddress) {
// 初始化並註冊一個 Channel 物件,因為註冊是非同步的過程,所以返回一個 ChannelFuture 物件。
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
// 繫結 Channel 的埠,並註冊 Channel 到 SelectionKey 中。
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise); // 繫結
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
promise.registered();
doBind0(regFuture, channel, localAddress, promise); // 繫結
}
}
});
return promise;
}
}
final ChannelFuture regFuture = initAndRegister();
初始化並註冊一個 Channel 物件。因為註冊是非同步的過程,所以返回一個 ChannelFuture 物件因為註冊是非同步的,有可能完成了,也有可能沒完成,所有程式碼中if-else分別處理已完成核未完成的情況。
doBind0(regFuture, channel, localAddress, promise);
,繫結 Channel 的埠,並註冊 Channel 到 SelectionKey 中。如果非同步註冊對應的 ChanelFuture 未完成,則呼叫
ChannelFuture#addListener(ChannelFutureListener)
方法,新增監聽器,在註冊完成後,進行回撥執行 doBind0(...) 方法的邏輯。
Netty是一個事件驅動的框架,我們可以看到在doBind()方法中的註冊和繫結,在Netty中是非同步事件,其中註冊就是將Channel註冊到reactor(之後講),繫結是指Channel獲得一個TCP埠。
在Netty中,但凡跟Future字眼扯上關係的,基本都是非同步,比如這裡的ChannelFuture。
相關文章
- Netty原始碼解析 -- 服務端啟動過程Netty原始碼服務端
- Netty服務端啟動過程相關原始碼分析Netty服務端原始碼
- Netty入門系列(1) --使用Netty搭建服務端和客戶端Netty服務端客戶端
- Netty入門一:服務端應用搭建 & 啟動過程原始碼分析Netty服務端原始碼
- Netty原始碼學習4——服務端是處理新連線的&netty的reactor模式Netty原始碼服務端React模式
- Gateway整合Netty服務GatewayNetty
- Netty原始碼分析(二):服務端啟動Netty原始碼服務端
- Netty系列文章之服務端啟動分析Netty服務端
- Netty服務端開發及效能最佳化Netty服務端
- Netty 系列之 Netty 百萬級推送服務設計要點Netty
- Kotlin + Netty 在 Android 上實現 Socket 的服務端KotlinNettyAndroid服務端
- netty原始碼分析之服務端啟動全解析Netty原始碼服務端
- Netty NioEventLoop 建立過程原始碼分析NettyOOP原始碼
- Netty NioEventLoop 啟動過程原始碼分析NettyOOP原始碼
- netty服務端監聽客戶端連線加入和斷開事件Netty服務端客戶端事件
- netty系列之:使用netty搭建websocket客戶端NettyWeb客戶端
- netty系列之:NIO和netty詳解Netty
- 基於Java NIO 寫的一個簡單版 Netty 服務端JavaNetty服務端
- 深入學習Netty(4)——Netty程式設計入門Netty程式設計
- netty系列之:netty中的Channel詳解Netty
- netty系列之:netty中的ByteBuf詳解Netty
- Netty原始碼解析 -- ChannelOutboundBuffer實現與Flush過程Netty原始碼
- netty叢集(一)-服務註冊發現Netty
- 【Netty】(4)—原始碼AbstractBootstrapNetty原始碼boot
- Netty原始碼學習5——服務端是如何讀取資料的Netty原始碼服務端
- netty系列之:netty中的frame解碼器Netty
- React 服務端渲染原理及過程React服務端
- Netty原始碼解析 -- ChannelPipeline機制與讀寫過程Netty原始碼
- netty系列之:netty中的核心解碼器jsonNettyJSON
- netty建立聊天室服務端及單機併發測試結果Netty服務端
- netty系列之:netty初探Netty
- Netty series: handling CORS in nettyNettyCORS
- TypeScript初步瞭解TypeScript
- netty系列之:netty中的自動解碼器ReplayingDecoderNetty
- Netty整合SpringMVC,實現高效的HTTP服務請求NettySpringMVCHTTP
- 【Netty】編解碼器Netty
- Netty1:初識NettyNetty
- Netty4.x原始碼分析Netty原始碼