欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析

 更新時間:2022年03月25日 10:03:43   作者:向南是個萬人迷  
這篇文章主要介紹了Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前文傳送門 Netty分布式Server啟動流程服務(wù)端初始化源碼分析

NioServerSocketChannel創(chuàng)建

我們?nèi)绻煜io, 則對channel的概念則不會陌生, channel在相當(dāng)于一個通道, 用于數(shù)據(jù)的傳輸

Netty將jdk的channel進(jìn)行了包裝, 并為其擴(kuò)展了更多的功能

在netty中也分為服務(wù)端channel和客戶端channel, 在Nio模式下, 服務(wù)端channel對應(yīng)的類為NioServerSocketChannel, 包裝的jdk的ServerSocketChannel

客戶端channel對應(yīng)的類為NioSocketChannel, 所包裝的jdk的類為SocketChannel

繼承關(guān)系

最簡單的繼承關(guān)系如下(經(jīng)簡化):

我們繼續(xù)看第一小節(jié)demo:

//創(chuàng)建boss和worker線程(1)
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
//創(chuàng)建ServerBootstrap(2)
ServerBootstrap b = new ServerBootstrap();
//初始化boss和work線程化兩個線程(3)
b.group(bossGroup, workerGroup)
        //聲明NioServerSocketChannel(4)
        .channel(NioServerSocketChannel.class)
        //初始化客戶端Handler(5)
        .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) {
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringEncoder());
                ch.pipeline().addLast(new ServerHandler());
            }
        });
//綁定端口(6)
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();

綁定端口

我們繼續(xù)看第六步, 綁定端口:

ChannelFuture f = b.bind(8888).sync();

在此, 我們看到綁定了8888端口

我們跟到bind(8888)方法中:

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}

端口封裝成socket地址對象

繼續(xù)跟bind方法:

public ChannelFuture bind(SocketAddress localAddress) {
    validate();
    return doBind(localAddress);
}

validate()做了一些屬性驗(yàn)證

我們繼續(xù)跟到doBind(localAddress)方法:

private ChannelFuture doBind(final SocketAddress localAddress) {
    //初始化并注冊(1)
    final ChannelFuture regFuture = initAndRegister();
    //獲得channel(2)
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }
    if (regFuture.isDone()) {
        ChannelPromise promise = channel.newPromise();
        //綁定(3) 
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        //去除非關(guān)鍵代碼
        return promise;
    }
}

去除了一些非關(guān)鍵的代碼, 重點(diǎn)關(guān)注注釋標(biāo)注的第一步, 初始化并注冊:

final ChannelFuture regFuture = initAndRegister();

跟進(jìn)initAndRegister()方法 創(chuàng)建channel

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        //創(chuàng)建channel
        channel = channelFactory.newChannel();
        init(channel);
    } catch (Throwable t) {
        //忽略非關(guān)鍵代碼
    }
    ChannelFuture regFuture = config().group().register(channel);
    //忽略非關(guān)鍵代碼
    return regFuture;
}

關(guān)注添加注釋的步驟, 創(chuàng)建channel, 這一點(diǎn)也是我們這節(jié)需要講明白的內(nèi)容

看這一步:

channel = channelFactory.newChannel();

這里channelFactory調(diào)用了newChannel()的這個方法, 這個方法從名字就不難理解, 是新建一個channel, 回顧下上一小節(jié), 這個channelFactory是在哪里初始化呢?

根據(jù)上一小節(jié)代碼, channelFactory是在Bootstrap的channelFactory ()方法初始化的:

public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    this.channelFactory = channelFactory;
    return (B) this;
}

而這個方法又是channel()方法中調(diào)用的:

public B channel(Class&lt;? extends C&gt; channelClass) {
    return channelFactory(new ReflectiveChannelFactory&lt;C&gt;(channelClass));
}

這里傳入ReflectiveChannelFactory對象就是初始化的channelFactory對象

所以newChannel()是調(diào)用ReflectiveChannelFactory對象的newChannel方法

跟到ReflectiveChannelFactory對象的newChannel方法中:

@Override
public T newChannel() {
    try { 
        return clazz.newInstance();
    } catch (Throwable t) {
        throw new ChannelException("Unable to create Channel from class " + clazz, t);
    }
}

我們看到這個clazz對象通過反射創(chuàng)建了channel, 這個clazz對象, 就是我們上一節(jié)提到過的, 初始化的NioServerSocketChannel的class對象

這里通過反射調(diào)用, 會創(chuàng)建一個NioServerSokectChannel

學(xué)習(xí)過nio的小伙伴都知道jdk的ServerSocketChannel, 用于接受鏈接事件, 而netty的NioServerSocketChannel是和jdk的channel有什么關(guān)系呢?

實(shí)際上netty的channel和jdk的channel的含義一樣, 也是一個通道, 只是netty為其做了擴(kuò)展, 而channel的事件處理, 也是通過jdk的channel去做的, 我們跟隨著NioServerSocketChannel的創(chuàng)建過程, 來了解他們之間的關(guān)聯(lián)關(guān)系

clazz.newInstance()通過反射創(chuàng)建一個NioServerSocketChannel對象, 首先會走到NioServerSocketChannel的構(gòu)造方法, 我們跟到他的構(gòu)造方法, 查看NioServerSocketChannel的創(chuàng)建過程

首先會調(diào)用它的無參構(gòu)造方法:

public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

我們看到這個構(gòu)造方法調(diào)用了另一個有參的構(gòu)造方法, 傳入?yún)?shù)是 newSocket(DEFAULT_SELECTOR_PROVIDER) 

我們首先看DEFAULT_SELECTOR_PROVIDER這個這變量:

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

看到這初始化了一個SelectorProvider對象, 而這個對象是通過靜態(tài)方法provider()創(chuàng)建的, SelectorProvider對象可以用于創(chuàng)建jdk底層的ServerSocketChannel

我們繼續(xù)跟到newSocket(DEFAULT_SELECTOR_PROVIDER)中:

private static ServerSocketChannel newSocket(SelectorProvider provider) {
    return provider.openServerSocketChannel();
}

去掉try-catch塊, 發(fā)現(xiàn)這個方法是通過SelectorProvider對象的openServerSocketChannel()方法創(chuàng)建一個jdk底層的ServerSocketChannel, 至此我們可以知道, 與NioServerSokectChannel綁定的jdk底層的ServerSocketChannel就是這么創(chuàng)建的

父類的構(gòu)造方法

那么創(chuàng)建之后如何與netty的channel綁定?繼續(xù)跟代碼

跟到this(newSocket(DEFAULT_SELECTOR_PROVIDER))中:

public NioServerSocketChannel(ServerSocketChannel channel) {
    super(null, channel, SelectionKey.OP_ACCEPT);
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

我們看到這里調(diào)用了父類的構(gòu)造方法,繼續(xù)往里跟:

protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent, ch, readInterestOp);
}

這里調(diào)用了其父類AbstractNioMessageChannel類的構(gòu)造方法, AbstractNioMessageChannel這個類同學(xué)們請記住, 有關(guān)是NioServerSocketChannel的父類, 代表著服務(wù)端channel的相關(guān)屬性和操作, 之后有關(guān)服務(wù)端channel的一些事件會在這個類中完成

我們看到這個類的構(gòu)造方法中又調(diào)用了它的父類的構(gòu)造方法, 我們繼續(xù)跟:

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
    //保存channel
    this.ch = ch;
    //綁定事件
    this.readInterestOp = readInterestOp;
    try {
        //設(shè)置為非阻塞
        ch.configureBlocking(false);
    } catch (IOException e) {
        //去掉非關(guān)鍵代碼
    }
}

這里又調(diào)用了其父類AbstractChannel的構(gòu)造方法, 跟進(jìn)去這個方法之前, 我們先往下看

首先看這一步:

this.ch = ch;

這步就是綁定jdk底層的ServerSocketChannel, 至此我們知道, jdk的channel和netty定義的channel是組合關(guān)系, netty的channel中有個jdk的channel的成員變量, 而這個成員變量就定義在AbstractNioChannel這個類當(dāng)中, 希望同學(xué)們將這個結(jié)論牢牢記住, 對以后的學(xué)習(xí)很有幫助

將jdk的channel設(shè)置為非阻塞模式

我們看到后面的這一步:

ch.configureBlocking(false);

這一步, 就是將jdk的channel設(shè)置為非阻塞模式, 這里熟悉Nio的同學(xué)應(yīng)該不會陌生, 這里不再贅述

 我們繼續(xù)跟到super(parent)中, 走到其父類AbstractChannel的構(gòu)造方法:

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}

首先看下這個parent, 這個parent是NioServerSocketChannel調(diào)用其父類構(gòu)造方法傳入的, 傳入的是null, 所以這一步AbstractChannel的屬性parent也是null, 這個parent, 我們之后再講客戶端channel的時候會講到

id = newId()是為每個channel創(chuàng)建一個唯一id

我們重點(diǎn)關(guān)注下后兩步:

unsafe = newUnsafe();
pipeline = newChannelPipeline();

這里初始化了兩個屬性unsafe, 和pipeline, 目前我們只需要知道這兩個屬性是在這里初始化的, 至于這兩個屬性的概念, 后面的章節(jié)會講到

以上就是創(chuàng)建NioServerSocketChannel的過程, 同學(xué)們可以課后跟進(jìn)源碼去熟悉鞏固

以上就是Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析的詳細(xì)內(nèi)容,更多關(guān)于Netty分布式server啟動流程N(yùn)io創(chuàng)建的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java泛型枚舉Annotation接口詳細(xì)解讀與Eclipse發(fā)展

    Java泛型枚舉Annotation接口詳細(xì)解讀與Eclipse發(fā)展

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • SpringBoot接口返回結(jié)果封裝方法實(shí)例詳解

    SpringBoot接口返回結(jié)果封裝方法實(shí)例詳解

    在實(shí)際項(xiàng)目中,一般會把結(jié)果放在一個封裝類中,封裝類中包含http狀態(tài)值,狀態(tài)消息,以及實(shí)際的數(shù)據(jù)。這里主要記錄兩種方式,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-09-09
  • java實(shí)現(xiàn)投票程序設(shè)計(jì)

    java實(shí)現(xiàn)投票程序設(shè)計(jì)

    這篇文章主要介紹了java實(shí)現(xiàn)投票程序設(shè)計(jì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Spring?Boot在啟動時執(zhí)行一次的功能實(shí)現(xiàn)

    Spring?Boot在啟動時執(zhí)行一次的功能實(shí)現(xiàn)

    這篇文章主要給大家介紹了關(guān)于Spring?Boot在啟動時執(zhí)行一次的功能實(shí)現(xiàn),在實(shí)習(xí)過程中,有時候會遇到一些項(xiàng)目啟動初始化的需求,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • 使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫分離

    使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫分離

    ShardingJDBC是一個輕量級的Java框架,提供了數(shù)據(jù)分片、讀寫分離、分布式主鍵生成等數(shù)據(jù)訪問功能,本文將給大家介紹如何使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫分離,需要的朋友可以參考下
    2024-01-01
  • Java利用Strategy模式實(shí)現(xiàn)堆排序

    Java利用Strategy模式實(shí)現(xiàn)堆排序

    策略設(shè)計(jì)模式(Strategy):可以整體的替換一個算法的實(shí)現(xiàn)部分,能夠整體的替換算法,能讓我們輕松地用不同方法解決同一個問題。本文將利用Strategy模式實(shí)現(xiàn)堆排序,感興趣的可以學(xué)習(xí)一下
    2022-09-09
  • Spring靜態(tài)代理和動態(tài)代理代碼詳解

    Spring靜態(tài)代理和動態(tài)代理代碼詳解

    這篇文章主要介紹了Spring靜態(tài)代理和動態(tài)代理代碼詳解,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • 詳解SpringBoot+Dubbo集成ELK實(shí)戰(zhàn)

    詳解SpringBoot+Dubbo集成ELK實(shí)戰(zhàn)

    這篇文章主要介紹了詳解SpringBoot+Dubbo集成ELK實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • SpringBoot集成Nacos的項(xiàng)目實(shí)踐

    SpringBoot集成Nacos的項(xiàng)目實(shí)踐

    本文主要介紹了SpringBoot集成Nacos的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • POI通過模板導(dǎo)出EXCEL文件的實(shí)例

    POI通過模板導(dǎo)出EXCEL文件的實(shí)例

    下面小編就為大家?guī)硪黄狿OI通過模板導(dǎo)出EXCEL文件的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08

最新評論