Netty分布式Server启动流程服务端初始化源码分析

 更新时间:2022年03月25日 08:34:31   作者:向南是个万人迷  
本章主要讲解server启动的关键步骤, 读者只需要了解server启动的大概逻辑, 知道关键的步骤在哪个类执行即可, 并不需要了解每一步的运作机制, 之后会对每个模块进行深度分析

第一节:服务端初始化

首先看下在我们用户代码中netty的使用最简单的一个demo:

//创建boss和worker线程(1)
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
//创建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();

相信这段代码使用过netty的同学应该都不陌生.这里每一步都用了注释和步骤序号进行标注, 为了方便学习过程中更容易的定位.每一步的讲解, 尽量自己也去跟到源码中, 这样会有个更深刻的理解

第一步, 创建两个线程组:

其中会调用NioEventLoopGroup()的构造方法, 其中的创建逻辑, 并不是这章的重点, 在这里大家只需要知道这里创建了两个线程组

第二步, 创建ServerBootstrap, 我们发现, 这里创建只调用了其无参的构造方法, 原因很简单, 就是参数太多, 尽量要用构造方法去初始化, 而是使用后面的build的方式

第三步, 初始化boss和work线程化两个线程

group方法

我们跟到group方法中去看:

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    //设置线程池组
    super.group(parentGroup);
    this.childGroup = childGroup;
    return this;
}

为了代码可读性, 去掉非关键代码(以后不再赘述), 我们看到这里初始化了自家的属性childGroup, 而这个属性就是我们传入的worker线程组, 而boss线程组则交给了其父类的group方法去做处理

我们点进去super.group(parentGroup), 进入到ServerBootstroop的父类AbstractBootstrap的group()方法:

public B group(EventLoopGroup group) {
    this.group = group;
    return (B) this;
}

看到在其父类初始化了boss线程

我们看到这个方法返回了this, 也就是ServerBootstroop自身, 这样通过自身对象不断的build进行属性初始化, 之后的方法也是如此

至此, worker和boss两个线程组初始化完毕

初始化成员变量

回到最开始的第四步, 再点进到channel(ServerSocketChannel.class)方法当中, 

我们看到AbsractServerBootstrap的channel(Class<? extends C> channelClass)方法:

public B channel(Class<? extends C> channelClass) {
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}

我们看到这个这返回的是channelFactory(new ReflectiveChannelFactory<C>(channelClass))方法, 并且传入一个ReflectiveChannelFactory对象的实例,

我们可以跟进去看下ReflectiveChannelFactory的构造方法:

public ReflectiveChannelFactory(Class<? extends T> clazz) {
    this.clazz = clazz;
}

这里初始化了一个成员变量clazz, 而这个clazz就是用户代码调用channel(NioServerSocketChannel.class)传入的NioServerSocketChannel的class对象

回到channelFactory(new ReflectiveChannelFactory<C>(channelClass))方法, 点进去, 我们看到:

public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
    return channelFactory((ChannelFactory<C>) channelFactory);
}

继续跟:

public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
    return channelFactory((ChannelFactory<C>) channelFactory);
}

跟到最后:

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

这里初始化了channelFactory, 而这个channelFactory就是刚才创建的ReflectiveChannelFactory对象, 这里我们记住这个对象中初始化了我们的NioServerSocket的class对象

至此, 我们的ServerSocketChannel的class对象初始化完成

初始化客户端Handler

我们跟到最开始的第五步, 初始化客户端Handler:

.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());
            }
        });

childHandler()方法比看起来比较复杂, 其实不难理解, 就是传入ChannelInitializer类子类的一个对象(有关匿名内部类不知道的同学可以找下相关资料学习下), 也就是一个Handler, 这个Handler是做什么的, 目前不需要关心, 以后会讲到, 这里我们只需知道这个方法传入一个handler对象

我们点进childHandler这个方法:

public ServerBootstrap childHandler(ChannelHandler childHandler) {
    this.childHandler = childHandler;
    return this;
}

发现同样非常简单的初始化了handler属性

这一小节至此结束, 只是初始化了ServerBootstrap的各个属性, 是不是非常简单

我们可以看到, 通过对象build的方式, 可以初始化非常多的属性, 并且代码要比构造方法的方式可读性要好的多, 同学们可以将这种思想用在自己的代码当中...

以上就是Netty源码分析Server启动流程的详细内容,更多关于NettyServer启动流程的资料请关注脚本之家其它相关文章!

相关文章

  • 关于IDEA配置Hibernate中遇到的问题解决

    关于IDEA配置Hibernate中遇到的问题解决

    这篇文章主要给大家介绍了关于IDEA配置Hibernate中遇到的问题,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • javaWeb传收参数方式总结示例分析

    javaWeb传收参数方式总结示例分析

    这篇文章主要为大家介绍了javaWeb传收参数方式总结示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • SpringBoot基于HttpMessageConverter实现全局日期格式化

    SpringBoot基于HttpMessageConverter实现全局日期格式化

    这篇文章主要介绍了SpringBoot基于HttpMessageConverter实现全局日期格式化,使用Jackson消息转换器,非常具有实用价值,需要的朋友可以参考下
    2018-12-12
  • Swagger2配置Security授权认证全过程

    Swagger2配置Security授权认证全过程

    这篇文章主要介绍了Swagger2配置Security授权认证全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java中内部类使用方法实战案例分析

    Java中内部类使用方法实战案例分析

    这篇文章主要介绍了Java中内部类使用方法,结合具体案例形式分析了Java内部类原理、调用方法及相关使用注意事项,需要的朋友可以参考下
    2019-09-09
  • JavaWeb入门:ServletContext详解和应用

    JavaWeb入门:ServletContext详解和应用

    这篇文章主要介绍了Java ServletContext对象用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-07-07
  • 使用SpringBoot内置web服务器

    使用SpringBoot内置web服务器

    这篇文章主要介绍了使用SpringBoot内置web服务器操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • java解析Excel的方法(xls、xlsx两种格式)

    java解析Excel的方法(xls、xlsx两种格式)

    这篇文章主要介绍了java解析Excel的方法(xls、xlsx两种格式),需要的朋友可以参考下
    2018-04-04
  • SpringBoot扩展点EnvironmentPostProcessor实例详解

    SpringBoot扩展点EnvironmentPostProcessor实例详解

    这篇文章主要介绍了SpringBoot扩展点EnvironmentPostProcessor的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • spring boot下mybatis配置双数据源的实例

    spring boot下mybatis配置双数据源的实例

    这篇文章主要介绍了spring boot下mybatis配置双数据源的实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论