【第15篇】netty服務(wù)端初始化流程詳細(xì)分析

1、 Channel與ChannelHandlerContext

  • Channel與ChannelHandlerContext都實(shí)現(xiàn)了AttributeMap,可以讓用戶(hù)附加一個(gè)或多個(gè)用戶(hù)定義的屬性,有時(shí)令用戶(hù)干到疑惑,一個(gè)Channel與一個(gè)ChannelHandlerContext擁有各種的用戶(hù)自定義的存儲(chǔ)
  • Netty4.1的版本解決了Attr方法的改變,減少ChannelHandlerContext對(duì)Map的創(chuàng)建,從而減少了內(nèi)存的使用(版本改良點(diǎn))

New and noteworthy in 4.1 請(qǐng)截圖

ChannelHandlerContext

ChannelHandlerContext

2、 初始化流程

  • ServerBootstrap類(lèi)的init方法在初始化流程很重要
  • NioEventLoopGroup繼承MutiEventLoopGroup類(lèi)

服務(wù)端初始化的步驟
1、創(chuàng)建ServerBootstrap啟動(dòng)輔助類(lèi),通過(guò)Builder模式進(jìn)行參數(shù)配置;
2、創(chuàng)建并綁定Reactor線(xiàn)程池EventLoopGroup;
4、設(shè)置并綁定服務(wù)端Channel通道類(lèi)型;
5、綁定服務(wù)端通道數(shù)據(jù)處理器責(zé)任鏈Handler;

3、ServerBootstrap初始化

  • ServerBootstrap是netty啟動(dòng)輔助類(lèi),通過(guò)Builder模式進(jìn)行參數(shù)設(shè)置初始化;ServerBootstrap繼承AbstracBootstrap類(lèi),需要對(duì)EventLoopGroup,Channel和ChannelHandler等參數(shù)進(jìn)行配置;
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
    private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap();
    private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap();
    private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
    private volatile EventLoopGroup childGroup;
    private volatile ChannelHandler childHandler;
}

image.png
  • EventLoop線(xiàn)程池初始化
    EventLoopGroup初始化是創(chuàng)建創(chuàng)建兩個(gè)NioEventLoopGroup類(lèi)型的Reactor線(xiàn)程池bossGroup和workGroup分別用來(lái)處理客戶(hù)端的連接請(qǐng)求和通道IO事件;
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b= new ServerBootstrap();
b.group(boosGroup,workGroup)
  • 通過(guò)group()方法設(shè)置EventLoop將bossGroup傳入到AbstractBootstrap中設(shè)置到group屬性上,將workGroup設(shè)置到ServerBootstrap的childGroup屬性上;如果只傳入了一個(gè)EventLoopGroup則最后傳入兩個(gè)相同的group;

public ServerBootstrap group(EventLoopGroup group) {
    return this.group(group, group);
}

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);
    if(childGroup == null) {
        throw new NullPointerException("childGroup");
    } else if(this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    } else {
        this.childGroup = childGroup;
        return this;
    }
}
  • super.group(parentGroup)方法對(duì)AbstractBootstrap的group屬性進(jìn)行設(shè)置
public B group(EventLoopGroup group) {
    if(group == null) {
        throw new NullPointerException("group");
    } else if(this.group != null) {
        throw new IllegalStateException("group set already");
    } else {
        this.group = group;
        return this;
    }
}

4、Channel通道初始化

  • Channel初始化主要是指對(duì)通道類(lèi)型進(jìn)行設(shè)置,常見(jiàn)的通道類(lèi)型主要有NioServerSocktChannel異步非阻塞服務(wù)端TCP通道,NioSocketChannel異步非阻塞客戶(hù)端通道,OioServerSocketChannel同步阻塞服務(wù)端通道,OioSocketChannel同步阻塞客戶(hù)端通道,NioDatagramChannel異步非阻塞UDP通道,OioDatagramChannel同步阻塞UDP通道等;
  • ChannelFactory通道工程類(lèi)設(shè)置,在serverBootstrap初始化過(guò)程中通過(guò)調(diào)用channel()方法進(jìn)行通道類(lèi)型設(shè)置
public B channel(Class<? extends C> channelClass) {
    if(channelClass == null) {
        throw new NullPointerException("channelClass");
    } else {
        return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass)));
    }
}
  • 根據(jù)傳入的Channe類(lèi)型初始化一個(gè)ChannelFactory類(lèi)型的工廠類(lèi),工廠類(lèi)中通過(guò)newChannel()方法創(chuàng)建Channel實(shí)例

private final Class<? extends T> clazz;

public ReflectiveChannelFactory(Class<? extends T> clazz) {
    if(clazz == null) {
        throw new NullPointerException("clazz");
    } else {
        this.clazz = clazz;
    }
}

public T newChannel() {
    try {
        return (Channel)this.clazz.newInstance();
    } catch (Throwable var2) {
        throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
    }
}
  • 通過(guò)channelFactory()方法將創(chuàng)建工廠類(lèi)實(shí)例指向AbstractoryBootstrap的channelFactory屬性
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    if(channelFactory == null) {
        throw new NullPointerException("channelFactory");
    } else if(this.channelFactory != null) {
        throw new IllegalStateException("channelFactory set already");
    } else {
        this.channelFactory = channelFactory;
        return this;
    }
}

5、Channel通道實(shí)例化

  • 配置好AbstractBootstrap的channelFactory工廠類(lèi),Channel的實(shí)例化通過(guò)ChannelFactory.newChannel()方法實(shí)現(xiàn);具體的newChannel()方法的調(diào)用鏈?zhǔn)牵?/li>
ServerBootstrap.bind() -> AbstractBootstrap.doBind() -> AbstractBootstrap.initAndRegister() -> ChannelFactory.newChannel();

public T newChannel() {
    try {
        return (Channel)this.clazz.newInstance();
    } catch (Throwable var2) {
        throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
    }
}
  • 通過(guò)clazz.newInstance()方法調(diào)用構(gòu)造器創(chuàng)建NioServerSocketChannel實(shí)例
public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
  • 調(diào)用newSocket()方法創(chuàng)建ServerSocketChannel實(shí)例,這里的ServerSocketChannel和NIO中的ServerSocketChannel是同一個(gè)東西,接下來(lái)會(huì)調(diào)用父類(lèi)構(gòu)造器對(duì)其進(jìn)行外部封裝和相關(guān)參數(shù)的配置;
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
    super((Channel)null, channel, 16);
    this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
}
  • 在 NioServerSocketChannsl 實(shí)例化過(guò)程中, 所需要做的工作
    調(diào)用 NioServerSocketChannel.newSocket(DEFAULT_SELECTOR_PROVIDER) 打開(kāi)一個(gè)新的 Java NIO ServerSocketChannel

AbstractNioChannel 中的屬性:

  • SelectableChannel ch 被設(shè)置為 Java ServerSocketChannel, 即 NioServerSocketChannel#newSocket 返回的 Java NIO ServerSocketChannel.
  • readInterestOp 被設(shè)置為 SelectionKey.OP_ACCEPT
  • SelectableChannel ch 被配置為非阻塞的 ch.configureBlocking(false)=
  • AbstractChannel(Channel parent) 中初始化

AbstractChannel 的屬性:

  • AbstractChannel 的屬性parent 屬性置為 null
  • unsafe 通過(guò)newUnsafe() 實(shí)例化一個(gè)unsafe對(duì)象, 它的類(lèi)型是 AbstractNioMessageChannel#AbstractNioUnsafe 內(nèi)部類(lèi)
  • pipeline 是 new DefaultChannelPipeline(this) 新創(chuàng)建的綁定管道實(shí)例.

NioServerSocketChannel 中的屬性:

ServerSocketChannelConfig config = new NioServerSocketChannelConfig(this, javaChannel().socket())

6、Channel通道注冊(cè)

  • 在channel通道創(chuàng)建和初始化完畢后,會(huì)通過(guò)group.register()方法將channel通道注冊(cè)到EventLoop線(xiàn)程池中;
final ChannelFuture initAndRegister() {
    // 去掉非關(guān)鍵代碼
    final Channel channel = channelFactory().newChannel();
    init(channel);
    ChannelFuture regFuture = group().register(channel);
}
  • 通過(guò)一系列的注冊(cè)方法調(diào)用:AbstractBootstrap.initAndRegister -> MultithreadEventLoopGroup.register -> SingleThreadEventLoop.register -> AbstractUnsafe.register,最終是通過(guò)Unsafe類(lèi)的register0()方法
private void register0(ChannelPromise promise) {
    boolean firstRegistration = neverRegistered;
    doRegister();
    neverRegistered = false;
    registered = true;
    safeSetSuccess(promise);
    pipeline.fireChannelRegistered();
    // Only fire a channelActive if the channel has never been registered. This prevents firing
    // multiple channel actives if the channel is deregistered and re-registered.
    if (firstRegistration && isActive()) {
        pipeline.fireChannelActive();
    }
}
  • register0()方法調(diào)用了doRegister()方法實(shí)現(xiàn)通道注冊(cè)到線(xiàn)程池中(EventLoop線(xiàn)程池會(huì)綁定一個(gè)selector選擇器)
@Override
protected void doRegister() throws Exception {
    // 省略錯(cuò)誤處理
    selectionKey = javaChannel().register(eventLoop().selector, 0, this);
}

7 handler處理器的添加過(guò)程

  • 我們可以自定義Handler處理器并將其加入到pipeline管道中,進(jìn)而像插件一樣自由組合各種handler完成具體的業(yè)務(wù)邏輯;添加handler的過(guò)程是獲取與channel通道綁定的管道pipeline然后將自定義的handler添加進(jìn)pipeline內(nèi)部維護(hù)的一個(gè)雙向鏈表;
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
 protected void initChannel(SocketChannel socketChannel) throws Exception {
    socketChannel.pipeline().addLast(new TimeServerHandler());
     }
});
  • Bootstrap.childerHandler方法接收一個(gè) ChannelHandler, 而我們傳遞的是一個(gè) 派生于ChannelInitializer的匿名類(lèi),它正好也實(shí)現(xiàn)了 ChannelHandler接口,因此將ChannelHandler實(shí)例賦值給ServerBootstrap的childHandler屬性;
public ServerBootstrap childHandler(ChannelHandler childHandler) {
    if(childHandler == null) {
        throw new NullPointerException("childHandler");
    } else {
        this.childHandler = childHandler;
        return this;
    }
}
  • 在啟動(dòng)服務(wù)端綁定端口時(shí)候最終通過(guò)調(diào)用initAndRegister()方法創(chuàng)建Channel實(shí)例,并將通過(guò)init()方法將系統(tǒng)定義的處理器ServerBootstrapAccptor添加到與channel綁定的pipeline通道中;
@Override
void init(Channel channel) throws Exception {
    ...
    ChannelPipeline p = channel.pipeline();

    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry<ChannelOption<?>, Object>[] currentChildOptions;
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs;

    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(Channel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            ChannelHandler handler = handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }
            pipeline.addLast(new ServerBootstrapAcceptor(
                    currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
        }
    });
}
  • 在ServerBootstrapAcceptor中重寫(xiě)了channelRead()方法,將自定義的handler處理器添加到管道中;
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    final Channel child = (Channel) msg;
    child.pipeline().addLast(childHandler);
    ...
    childGroup.register(child).addListener(...);
}
  • 服務(wù)器端的 handler 與 childHandler 的區(qū)別與聯(lián)系:

  • 服務(wù)器 NioServerSocketChannel 的 pipeline 中添加的是 handler 與 ServerBootstrapAcceptor.

  • 當(dāng)有新的客戶(hù)端連接請(qǐng)求時(shí), ServerBootstrapAcceptor.channelRead 中負(fù)責(zé)新建此連接的NioSocketChannel并添加 childHandler 到 NioSocketChannel 對(duì)應(yīng)的pipeline中, 并將此channel綁定到workerGroup中的某個(gè)eventLoop中;

  • handler是在accept階段起作用, 它處理客戶(hù)端的連接請(qǐng)求,ServerBootstrap也能設(shè)置handler()方法添加ServerSocketChannel的自定義處理器;

8、 OIO(掌握點(diǎn))

  • OIO是阻塞編程模型,一個(gè)連接過(guò)來(lái)服務(wù)端會(huì)啟用一個(gè)線(xiàn)程專(zhuān)門(mén)服務(wù)這個(gè)連接,而客戶(hù)端一直等待響應(yīng)返回?cái)?shù)據(jù)(有多少個(gè)就會(huì)創(chuàng)建多少個(gè)Thread)
  • OioServerSocketChannel同步阻塞服務(wù)端通道,OioSocketChannel同步阻塞客戶(hù)端通道,NioDatagramChannel異步非阻塞UDP通道,OioDatagramChannel同步阻塞UDP通道等
  • OioServerSocketChannel與NioDatagramChannel類(lèi)關(guān)系圖


    OioServerSocketChannel

    NioDatagramChannel

9、 lsof命令

  • lsof -i :8080 查看8080端口進(jìn)程命令,lsof 代表list open file 打開(kāi)列表文件的意思

10、總結(jié)

Netty服務(wù)端的初始化主要是創(chuàng)建初始化輔助類(lèi)ServerBootstrap,并對(duì)輔助類(lèi)的相關(guān)參數(shù)進(jìn)行初始化包括EventLoop線(xiàn)程池,Channle通道類(lèi)型和ChannleHandler通道處理器等;在調(diào)用bind()方法進(jìn)行端口綁定時(shí),會(huì)根據(jù)ServerBootsrap中的初始化參數(shù)啟動(dòng)服務(wù)端,具體的啟動(dòng)流程為:

  • 創(chuàng)建ServerBootstrap啟動(dòng)輔助類(lèi)實(shí)例,并對(duì)其Channel,EventLoopGroup,Handler等參數(shù)進(jìn)行配置;

  • 調(diào)用bootstrap.bind()方法時(shí)觸發(fā)啟動(dòng),會(huì)根據(jù)配置的Channle類(lèi)型創(chuàng)建Channel實(shí)例,比如NioServerSocketChannel等

  • 在實(shí)例化Channel時(shí)候會(huì)初始化Pipeline管道并與AbstractChannel綁定

  • 將channel管道注冊(cè)到EventLoopGroup線(xiàn)程池中,從線(xiàn)程池中輪詢(xún)獲取一個(gè)線(xiàn)程EventLoop并與之綁定;

  • 啟動(dòng)線(xiàn)程,線(xiàn)程執(zhí)行綁定的selector的select()方法監(jiān)聽(tīng)注冊(cè)的channel的狀態(tài),并執(zhí)行定時(shí)任務(wù)

  • NioServerSocketChannel

推薦學(xué)習(xí)博客

此文章內(nèi)容來(lái)自服務(wù)端初始化和個(gè)人學(xué)習(xí)過(guò)程中整理記錄筆記的摘要

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容