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. OSSpinLockLock加锁机制,保证线程安全并且性能高

    在aspect_add.aspect_remove方法里面用了aspect_performLocked, 而aspect_performLocked方法用了OSSpinLockLock加锁机制,保证线 ...

  2. 禁用wps的云文档,恢复到清爽的状态

    wps安装完成后,默认会开启云文档功能,每次打开表格.文档都会显示乱七八糟的一些东西,很麻烦 不得已只好手动为wps“瘦身”: 在wps表格或者文档的快捷方式上右键,选择打开文件所在位置 找到一个最新 ...

  3. Docker镜像搭建Linux下samba共享目录

    Samba 是 SMB/CIFS 网络协议的重新实现, 它作为 NFS 的补充使得在 Linux.OS/2.DOS 和 Windows 系统中进行文件共享.打印机共享更容易实现.SMB协议是客户机/服 ...

  4. 「GXOI / GZOI2019」与或和

    题目 广西和贵州的省选?好像很神仙的样子啊 之后发现这是一道水题 我们显然应该拆位考虑 显然我们应该对于每一位都拆一下看看这一位是\(0/1\) 显然我们如果找到一个全是\(1\)的矩阵,那么这一位的 ...

  5. P2278 [HNOI2003]操作系统

    题目描述 写一个程序来模拟操作系统的进程调度.假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的.其中运行优先级用自然数表示,数字越大,则优先级越高. 如果一个进程到达的时 ...

  6. A NB群友 【记忆化搜索】(2019年华南理工大学程序设计竞赛(春季赛))

    冲鸭!去刷题:https://ac.nowcoder.com/acm/contest/625/A 题目描述 CC是著名的算法竞赛选手,他不仅人长得帅,而且技术了得,自然而然就有了许多粉丝. 为了能帮助 ...

  7. R多线程并行计算

    先上代码案例: 主要的操作: library(parallel);#加载并行计算包 cl <- makeCluster(8);# 初始化cpu集群 clusterEvalQ(cl,library ...

  8. Kafka设计解析(八)Exactly Once语义与事务机制原理

    转载自 技术世界,原文链接 Kafka设计解析(八)- Exactly Once语义与事务机制原理 本文介绍了Kafka实现事务性的几个阶段——正好一次语义与原子操作.之后详细分析了Kafka事务机制 ...

  9. Spring事务(二)事务自定义标签

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.注册 InfrastructureAdvisorAutoPr ...

  10. vue实现菜单切换

    vue实现菜单切换,点击菜单导航切换不同的内容以及为当前点击的选项添加样式,或者组件. method里: css: html代码: <nav> <ul> <li> ...