前言

根据前文我们知道,NioEventLoopGroup和NioEventLoop是netty对Reactor线程模型的实现,而本文要说的ServerBootstrap是对上面二者的整合与调用,是一个统筹者和协调者。具体netty使用的是Reactor单线程模型还是多线程模型、抑或者主从多线程模型,都是ServerBootstrap的不同配置决定的。

下面照例粘贴一下示例demo(以Reactor多线程模式构建),开始正文。

 public class NettyDemo1 {
// netty服务端的一般性写法
public static void main(String[] args) {
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new NettyServerHandler());
}
});
ChannelFuture channelFuture = bootstrap.bind(90);
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}

一、ServerBootstrap的初始化

ServerBootstrap的无参构造器啥都没做,它使用的build模式给属性赋值,即上面示例中看到的,每执行一个赋值方法都会返回当前对象的引用使得可以继续链式调用。下面挨个方法追踪。

 public ServerBootstrap() { }

1、ServerBootstrap.group方法

ServerBootstrap有两个可用重载group方法(如下的两个),其中接收一个group入参的方法会调用有两个入参的group方法,只是两个参数传同一个group。这两个group方法决定了netty使用的Reactor线程模型的类型,一个group入参的方法对应Reactor单线程模型,两个入参且不是同一个group的方法对应Reactor多线程模型或主从多线程模型(具体是哪一种取决于实例化parentGroup时的线程数)。此处只是提一下,先有个印象,后面会对线程模型进行详细研究。

 public ServerBootstrap group(EventLoopGroup group) {
return group(group, group);
}
 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
ObjectUtil.checkNotNull(childGroup, "childGroup");
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}

可以看到上述group方法对两个入参进行了不同位置的赋值,将第一个参数parentGroup传给了父类AbstractBootstrap的group方法,如下,即最终赋值给了AbstractBootstrap中的group属性。第二个参数直接赋值给了ServerBootstrap的childGroup属性。

 public B group(EventLoopGroup group) {
ObjectUtil.checkNotNull(group, "group");
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return self();
}

2、ServerBootstrap.option/childOption方法和ServerBootstrap.attr/childAttr方法

这四个方法只是做了属性的赋值,分别赋值给了AbstractBootstrap的options属性和attrs属性以及ServerBootstrap的childOptions属性和childAttrs属性。

 public <T> B option(ChannelOption<T> option, T value) {
ObjectUtil.checkNotNull(option, "option");
if (value == null) {
synchronized (options) {
options.remove(option);
}
} else {
synchronized (options) {
options.put(option, value);
}
}
return self();
}
 public <T> B attr(AttributeKey<T> key, T value) {
ObjectUtil.checkNotNull(key, "key");
if (value == null) {
synchronized (attrs) {
attrs.remove(key);
}
} else {
synchronized (attrs) {
attrs.put(key, value);
}
}
return self();
}

3、ServerBootstrap.channel方法

调用的是父类AbstractBootstrap的channel方法:

 public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}

可以看到先封装成了一个ReflectiveChannelFactory对象,然后调用channelFactory方法,下面挨个看。ReflectiveChannelFactory的构造器如下,可见就是将传入class对象的构造器取出来赋值,此时constructor存放的就是NioServerSocketChannel的构造器。

public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}

channelFactory方法的工作是将上面创建的ReflectiveChannelFactory对象赋值给AbstractBootstrap的channelFactory属性:

 public B channelFactory(ChannelFactory<? extends C> channelFactory) {
ObjectUtil.checkNotNull(channelFactory, "channelFactory");
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
} this.channelFactory = channelFactory;
return self();
}

4、ServerBootstrap.handler方法和ServerBootstrap.childHandler方法

handler方法的入参赋值给了AbstractBootstrap的handler属性,childHandler方法的入参赋值给了ServerBootstrap的childHandler属性。看到这里想必园友们也能看出ServerBootstrap的赋值规律了,凡是child开头的都放在ServerBootstrap中,而不带child的大多放在其父类ABstractBootstrap中。

 public B handler(ChannelHandler handler) {
this.handler = ObjectUtil.checkNotNull(handler, "handler");
return self();
}
 public ServerBootstrap childHandler(ChannelHandler childHandler) {
this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
return this;
}

5、完成赋值后ServerBootstrap的快照图

小结

ServerBootstrap的初始化过程看起来赋了很多值,但都只是做了准备工作,看起来轻松又简单,但请注意,这是暴风雨前宁静。前面的各种赋值到底有什么用处?很多属性分为有child前缀和没有child前缀,这样设置又有什么意图?下一期将进入ServerBootstrap的bind方法,这是netty的深水区,很多谜底也将在这里得到揭晓,敬请期待!

Netty源码学习系列之2-ServerBootstrap的初始化的更多相关文章

  1. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  2. Netty源码学习系列之1-netty的串行无锁化

    前言 最近趁着跟老东家提离职之后.到新公司报道之前的这段空闲时期,着力研究了一番netty框架,对其有了一些浅薄的认识,后续的几篇文章会以netty为主,将近期所学记录一二,也争取能帮未对netty有 ...

  3. Netty源码学习系列之5-NioEventLoop的run方法

    前言     NioEventLoop的run方法,是netty中最核心的方法,没有之一.在该方法中,完成了对已注册的channel上来自底层操作系统的socket事件的处理(在服务端时事件包括客户端 ...

  4. Netty源码学习系列之1-NioEventLoopGroup的初始化

    前言 NioEventLoopGroup是netty对Reactor线程组这个抽象概念的具体实现,其内部维护了一个EventExecutor数组,而NioEventLoop就是EventExecuto ...

  5. 【Netty源码学习】ServerBootStrap

    上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...

  6. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

  7. Netty 源码分析系列(二)Netty 架构设计

    前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...

  8. Netty源码阅读(一) ServerBootstrap启动

    Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

  9. JDK源码学习系列05----LinkedList

                                             JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...

随机推荐

  1. Shell简单实现多线程

        一.目的 解决Shell脚本单线程下效率低下的问题 二.适用场景 需要在Linux系统执行同一项命令,但是针对不同的对象,例如PING检测主机,当然可以延展,只要是命令之间不会产生冲突就可以了 ...

  2. B. Modulo Sum dp

    https://codeforces.com/contest/577/problem/B 先读懂题意,substring 这个是子串说明不可以跳 subsequence这个是子序列可以跳 这个题目是一 ...

  3. 小程序-for循环遍历的使用

    .js文件: Page({ /** * 页面的初始数据 */ data: { datas:[ { title: '提交申请', txt: '选择服务类型,填写基本信息,提交' }, { title: ...

  4. Golang遍历删除数组

    Golang 做数字切片 package main import "fmt" /*遍历删除数组示例*/ func main() { //定义一个数组 a1 := []int{1, ...

  5. 进程和线程—Python多线程编程

    进程和线程 进程 进程是一个执行中的程序.每个进程都拥有自己的地址空间.内存.数据栈以及其它用于跟踪执行的辅助数据. 一个程序运行就是一个进程(比如 QQ.微信或者其它软件): 进程可以通过派生新的进 ...

  6. springboot+vue前后端免费开源

    序言 继上一篇 一套管理系统基础模版 详细梳理一下安装流程,功能说明,开发规范等. 后端项目结构? 如何从零搭建环境开发? 如何打包部署? 接入开发及规范 项目地址 小结 后端项目结构 ​ shop- ...

  7. css段落样式

    字间距 letter-spacing 首行缩进 text-indent

  8. Android CodeReview 些许总结

    CodeReview些许总结 1:使用Handler的时候,使用handler.post(Runnable);,hanler与类尽量保持弱引用关系,或者使用静态的handler对象 public Ha ...

  9. Flutter不能做什么:局限性

    老孟导读:您在网络上一定看过很多Flutter如何优秀的.如何完美的文章,而这篇文章将会告诉你Flutter不能做什么,注意并不是Flutter的缺点,比如第三方插件少.Dart不流行等,在我看来这都 ...

  10. vue打包 报错问题记录

    1.  assetsPublicPath: '/' 修改为 assetsPublicPath: './'   2. untils.js里面增加   publicPath: '../../'  重新运行 ...