zoukankan      html  css  js  c++  java
  • Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化

    Netty源码分析第一章:  Server启动流程

     

    概述:

            本章主要讲解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的方式

    第三步, 初始化bosswork线程化两个线程

     

    我们跟到group方法中去看:

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

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

     

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

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

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

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

    至此, workerboss两个线程组初始化完毕

     

    回到最开始的第四步, 再点进到channel(ServerSocketChannel.class)方法当中, 我们看到AbsractServerBootstrapchannel(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)传入的NioServerSocketChannelclass对象

     

    回到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对象, 这里我们记住这个对象中初始化了我们的NioServerSocketclass对象

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

     

    我们跟到最开始的第五步, 初始化客户端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的方式, 可以初始化非常多的属性, 并且代码要比构造方法的方式可读性要好的多, 同学们可以将这种思想用在自己的代码当中...

    上一节: 前言, 概述及目录

    下一节: NioServerSocketChannel的创建

  • 相关阅读:
    开源界的 5 大开源许可协议
    如何选择开源许可证?
    Ubuntu下Qt编译报错“cannot find -lGL”的解决方案
    How to Cracked Sublime Text 3 Build 3065 in Ubuntu (Linux)
    一个C语言宏展开问题
    C语言预处理运算符
    Linux线程编程之信号处理
    Linux终端多用户通信实用命令
    守护进程接收终端输入的一种变通性方法(二)
    通过printf设置Linux终端输出的颜色和显示方式
  • 原文地址:https://www.cnblogs.com/xiangnan6122/p/10202257.html
Copyright © 2011-2022 走看看