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的方式

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

我们跟到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:

.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的创建

Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化的更多相关文章

  1. Netty源码分析第3章(客户端接入流程)---->第4节: NioSocketChannel注册到selector

    Netty源码分析第三章: 客户端接入流程 第四节: NioSocketChannel注册到selector 我们回到最初的NioMessageUnsafe的read()方法: public void ...

  2. Netty源码分析第3章(客户端接入流程)---->第5节: 监听读事件

    Netty源码分析第三章: 客户端接入流程 第五节: 监听读事件 我们回到AbstractUnsafe的register0()方法: private void register0(ChannelPro ...

  3. Netty源码分析第3章(客户端接入流程)---->第1节: 初始化NioSockectChannelConfig

    Netty源码分析第三章: 客户端接入流程 概述: 之前的章节学习了server启动以及eventLoop相关的逻辑, eventLoop轮询到客户端接入事件之后是如何处理的?这一章我们循序渐进, 带 ...

  4. Netty源码分析第3章(客户端接入流程)---->第2节: 处理接入事件之handle的创建

    Netty源码分析第三章: 客户端接入流程 第二节: 处理接入事件之handle的创建 上一小节我们剖析完成了与channel绑定的ChannelConfig初始化相关的流程, 这一小节继续剖析客户端 ...

  5. Netty源码分析第3章(客户端接入流程)---->第3节: NioSocketChannel的创建

    Netty源码分析第三章: 客户端接入流程 第三节: NioSocketChannel的创建 回到上一小节的read()方法: public void read() { //必须是NioEventLo ...

  6. Netty源码分析第1章(Netty启动流程)---->第2节: NioServerSocketChannel的创建

    Netty源码分析第一章:  Server启动流程 第二节:NioServerSocketChannel的创建 我们如果熟悉Nio, 则对channel的概念则不会陌生, channel在相当于一个通 ...

  7. Netty源码分析第1章(Netty启动流程)---->第3节: 服务端channel初始化

    Netty源码分析第一章:Netty启动流程   第三节:服务端channel初始化 回顾上一小节的initAndRegister()方法: final ChannelFuture initAndRe ...

  8. Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用

    Netty源码分析第一章:Netty启动流程   第四节:注册多路复用 回顾下以上的小节, 我们知道了channel的的创建和初始化过程, 那么channel是如何注册到selector中的呢?我们继 ...

  9. Netty源码分析第1章(Netty启动流程)---->第5节: 绑定端口

    Netty源码分析第一章:Netty启动步骤 第五节:绑定端口 上一小节我们学习了channel注册在selector的步骤, 仅仅做了注册但并没有监听事件, 事件是如何监听的呢? 我们继续跟第一小节 ...

随机推荐

  1. Perl之my与local

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/sunshoupo211/article/details/31745909    在函数定义中,使用m ...

  2. Apache服务器下使用 ab 命令进行压力测试

    ab是Apache超文本传输协议(HTTP)的性能测试工具. 其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求. #ab -v可以看出其基本信息 ...

  3. PHP eval() 函数

    定义和用法 eval() 函数把字符串按照 PHP 代码来计算. 该字符串必须是合法的 PHP 代码,且必须以分号结尾. 如果没有在代码字符串中调用 return 语句,则返回 NULL.如果代码中存 ...

  4. Loj #2256. 「SNOI2017」英雄联盟

    题目 我就是个丝薄 如果要用\(dp_i\)表示凑出\(i\)的最小花费显然不可能的 之后大力猜想能凑出来的状态不会很多,我的暴力也告诉我不是很多,好像也确实不多的样子,大概\(4e4\)左右 但是我 ...

  5. jenkins持续化集成工具 centos 6.5安装

    1.wget 下载war包,即一键部署包 wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war 2.java命令安装 java -j ...

  6. html手机网页自适应宽度

    #在head之间加如下代码即可 <meta name="viewport" content="width=device-width, initial-scale=1 ...

  7. 用C#给程序加启动画面并只允许一个应用程序实例运行

    . 启动画面类: public class SplashForm : System.Windows.Forms.Form { private System.Windows.Forms.PictureB ...

  8. JavaScript实现计时器

    var myVar=setInterval(function(){myTimer()},1000); function myTimer() { var d = new Date(); document ...

  9. P1481 魔族密码

    题目描述 风之子刚走进他的考场,就…… 花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花) 风之子:我呕……(杀死人的眼神)快说题目!否则……-_-### 花花:……咦好冷我们现在 ...

  10. sql函数:开窗函数简介

    与聚合函数一样,开窗函数也是对行集组进行聚合计算,但是普通聚合函数每组只能返回一个值,而开窗函数可以每组返回多个值. 实验一比如我们想查询每个工资小于5000元的员工信息(城市以及年龄),并且在每行中 ...