为什么80%的码农都做不了架构师?>>>   

概述

ServerBootstrap是Netty提供的一个服务端工具类,通过设置ChanneFactory,ChannelPipelineFactory,用户可以很方便的启动一个服务端。

ServerBootstrap是做什么的

ServerBootstrap是一个帮助类,用来创建服务端的Channel以监听来自客户端的连接。

面向连接

ServerBootstrap只支持面向连接的传输,比如TCP/IP,如果是没有连接的传输,比如UDP/IP这样,就需要使用ConnectionlessBootstrap。

Parent and Child Channel

ServerBootstrap通过bind()方法使用属性ChannelFactory来创建服务端的Channel,以监听并且accept客户端的连接。服务端的Channel被称为parent Channel,来自客户端的连接被称为child Channel。

配置Channel

使用Options来设置parent and child Channel的可选参数,其中child Channel需要使用child.前缀。

ServerBootstrap b = ...;// Options for a parent channel
b.setOption("localAddress", new InetSocketAddress(8080));
b.setOption("reuseAddress", true);// Options for its children
b.setOption("child.tcpNoDelay", true);
b.setOption("child.receiveBufferSize", 1048576);

设置Channel Pipeline

Netty使用ChannelPipeline来处理和流转IO事件。parent Channel的Pipeline是由ServerBootstrap内部创建的,并且加入Binder的内部类作为ChannelHandler。我们可以设置ServerBootstrap的属性parentHandler,一旦设置之后parentHandler就会被追加到parent Pipeline中用来我们自定义的ChannelHandler。

child Pipeline有两种方式可以设置,一种方式是通过setPipelineFactory(ChannelPipelineFactory)设置,每个child Channel都会通过ChannelPipelineFactory创建新的ChannelPipeline,是推荐的方式。另一种方式通过setPipeline(ChannelPipeline)设置,这个方法内部会创建ChannelPipelineFactory,复用设置的ChannelPipeline的内部ChannelHandler。

不同配置,不同Channel

ServerBootstrap本身并不是占用资源,而是交给ChannelFactory来处理,官网文档说可以使用同一个ChannelFactory来创建多个ServerBootstrap,每个ServerBootstrap都可以使用不同的配置,从而创建不同的Channel(没见过这种需要。)

ServerBootstrap创建和启动过程

Netty为我们提供ServerBootstrap作为工具来方便的启动服务端,使用起来也很简单,一般分为这几步:

  • 创建ChannelFactory
  • 创建ChannelPipelineFactory
  • 创建ServerBootstrap实例、设置ChannelFactory和ChannelPipelineFactory
  • 调用bind方法

1、创建ChannelFactory

这个ChannelFactory在启动时候会创建parent Channel也就是服务的Channel以监听来自客户端的连接。

ChannelFactory是用来创建parent Channel

2、创建ChannelPipelineFactory

在accept Channel之后会使用这个ChannelPipelineFactory创建ChannelPipeline用来处理IO事件。常见的使用方法是使用Channels.pipeline()创建一个DefaultChannelPipeline,我们往里添加自定义的ChannelHandler即可。

ChannelPipelineFactory是用来服务child Channel

3、设置ChannelFactory和ChannelPipelineFactory

创建ServerBootstrap实例,设置ChannelFactory和ChannelPipelineFactory属性。

4、调用bind()方法启动,绑定在指定端口。

官网示例(也是常用使用方式,Dubbo就是这样的,设计的简约而不简单)

// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool()));// Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {public ChannelPipeline getPipeline() throws Exception {return Channels.pipeline(new EchoServerHandler());}
});// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port));

bind()绑定过程

ServerBootstrap通过调用bind()方法来启动服务端。绑定方法很简单,首先创建parent的ChannelPipeline,然后使用ChannelFactory创建Channel,结束。

public Channel bind(final SocketAddress localAddress) {ChannelFuture future = bindAsync(localAddress);// Wait for the future.future.awaitUninterruptibly();if (!future.isSuccess()) {future.getChannel().close().awaitUninterruptibly();throw new ChannelException("Failed to bind to: " + localAddress, future.getCause());}return future.getChannel();
}public ChannelFuture bindAsync(final SocketAddress localAddress) {if (localAddress == null) {throw new NullPointerException("localAddress");}// 设置bossPipelineBinder binder = new Binder(localAddress);ChannelHandler parentHandler = getParentHandler();ChannelPipeline bossPipeline = pipeline();bossPipeline.addLast("binder", binder);if (parentHandler != null) {bossPipeline.addLast("userHandler", parentHandler);}// 创建parent ChannelChannel channel = getFactory().newChannel(bossPipeline);final ChannelFuture bfuture = new DefaultChannelFuture(channel, false);binder.bindFuture.addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) throws Exception {if (future.isSuccess()) {bfuture.setSuccess();} else {// Call close on bind failurebfuture.getChannel().close();bfuture.setFailure(future.getCause());}}});return bfuture;
}

分析方法过程:

  1. 创建parent ChannelPipeline,添加Binder、外部设置的parentChannelHandler,这个Pipeline是给parent Channel服务的
  2. 使用ChannelFactory创建Channel,是parent Channel

Binder类是ServerBootstrap内部类,是一个UpstreamHandler,处理三个事件:channelOpen、childChannelOpen、exceptionCaught。

NioServerSocketChannelFactory创建NioServerSocketChannel,在NioServerSocketChannel的构造函数中会触发一个ChannelOpen的事件传入Pipeline中,这个Pipeline就是在ServerBootstrap的bind()方法里创建的parent Pipeline。而ChannelOpen是一个UpstreamEvent,因此Binder类就会执行相应的逻辑。

关键代码

// NioServerSocketChannel的构造函数中执行
socket = ServerSocketChannel.open();
socket.configureBlocking(false);
fireChannelOpen(this);      // Binder类的channelOpen方法,最后执行channel的bind方法
evt.getChannel().bind(localAddress).addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) throws Exception {if (future.isSuccess()) {bindFuture.setSuccess();} else {bindFuture.setFailure(future.getCause());}}
});// NioServerSocketChannel的bind方法
channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(channel, future, ChannelState.BOUND, localAddress));// NioServerSocketPipelineSink,调用NioServerBoss的bind方法
case BOUND:if (value != null) {((NioServerBoss) channel.boss).bind(channel, future, (SocketAddress) value);} else {((NioServerBoss) channel.boss).close(channel, future);}break;// NioServerBoss中创建RegisterTask
void bind(final NioServerSocketChannel channel, final ChannelFuture future,final SocketAddress localAddress) {registerTask(new RegisterTask(channel, future, localAddress));
}// RegisterTask中执行nio的bind和注册到Selector,属性的nio知识点
channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog());
bound = true;future.setSuccess();
fireChannelBound(channel, channel.getLocalAddress());
channel.socket.register(selector, SelectionKey.OP_ACCEPT, channel);

流程分析:

  1. NioServerSocketChannel构造方法创建Java nio的ServerSocketChannel;
  2. NioServerSocketChannel构造方法中触发OPEN的UpstreamEvent;
  3. Binder类中channelOpen()方法中调用Channel的bind()方法;
  4. NioServerSocketChannel的bind()方法触发一个BOUND的DownstreamEvent;
  5. NioServerSocketPipelineSink,调用NioServerBoss的bind()方法;
  6. NioServerBoss中创建RegisterTask,RegisterTask是一个Runnable对象,run()方法中执行NIO的相关操作,真正处理IO的地方
  7. ServerSocketChannel的bind方法,ServerSocketChannel注册到Selector,事件是OP_ACCEPT

总体的看来,ServerBootstrap内部将任务交给了Binder和ChannelFactory,进一步说其实是Channel来处理。通过一系列的事件触发,最终调用JDK NIO的ServerSocketChannel完成启动并注册监听。

ServerBootstrap没做什么,都是ServerChannelFactory在处理,想要理清楚Netty的服务端,就得剖析NioServerSocketChannelFactory。

思考一下

为什么不直接在ServerBootstrap的bind方法里直接执行Channel的bind方法呢?我觉得是想把复杂的逻辑剥离出来到Binder这个内部类里。may be

相关阅读

NioServerSocketChannelFactory分析

转载于:https://my.oschina.net/cregu/blog/2874332

Netty3之ServerBootstrap分析相关推荐

  1. netty4.0.x源码分析—bootstrap

    Bootstrap的意思就是引导,辅助的意思,在编写服务端或客户端程序时,我们都需要先new一个bootstrap,然后基于这个bootstrap调用函数,添加eventloop和handler,可见 ...

  2. Netty3 源代码分析 - NIO server绑定过程分析

    Netty3 源代码分析 - NIO server绑定过程分析      一个框架封装的越好,越利于我们高速的coding.可是却掩盖了非常多的细节和原理.可是源代码可以揭示一切. 服务器端代码在指定 ...

  3. Wangle源码分析:ServerBootstrap

    2019独角兽企业重金招聘Python工程师标准>>> ServerBootstrap介绍       ServerBootstrap,顾名思义,它是作为Wangle服务端的一个启动 ...

  4. 志宇-dubbo源码分析

    dubbo源码分析 文档 dubbo加载配置文件 dubboSPI dubbo服务提供 1.校验配置信息 2.创建URL 3.本地注册 4.远程注册 4.1 开启netty服务端 4.2 连接注册中心 ...

  5. 一次Dubbo拥堵的分析

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:nxlhero https://blog.51cto.com ...

  6. Netty Channel源码分析

    原文:https://wangwei.one/posts/netty-channel-source-analyse.html 前面,我们大致了解了Netty中的几个核心组件.今天我们就来先来介绍Net ...

  7. Netty Pipeline源码分析(2)

    原文链接:https://wangwei.one/posts/net... 前面 ,我们分析了Netty Pipeline的初始化及节点添加与删除逻辑.接下来,我们将来分析Pipeline的事件传播机 ...

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

    Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用 Netty源码分析第一章:Netty启动流程   第四节:注册多路复用 回顾下以上的小节, 我们知道了channe ...

  9. netty 5 alph1源码分析(服务端创建过程)

    研究了netty的服务端创建过程.至于netty的优势,可以参照网络其他文章.<Netty系列之Netty 服务端创建>是 李林锋撰写的netty源码分析的一篇好文,绝对是技术干货.但抛开 ...

最新文章

  1. js基础--数据类型检测的相关知识
  2. 通俗说一下python和人工智能有什么关系
  3. 设置3d rotationY 旋转之后元件大小改变解决方案
  4. 【Python】字符串和变量拼接的写法
  5. 安卓9与10的系统要求_代码开源!支持RISC-V架构的安卓系统终于来了!
  6. 猴子选大王 (20 分)
  7. python原理_强化学习:原理与Python实现
  8. android 音乐游戏,手速党的胜利 -- 音乐游戏专题 #iOS #Android
  9. 我要养成写博客的好习惯!
  10. 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。...
  11. UVA10405 Longest Common Subsequence【LCS+DP】
  12. eclipse根据wsdl文件生成webservice客户端
  13. Atitit glb 1tie 2tie city lst 一二线城市列表数据约50个一线城市Alpha ++ 阿尔法++,,London 伦敦,,New York 纽约,,Alpha +
  14. Java连接数据库导致连接数占满
  15. 计算机二级c语言f7保存,国家计算机二级c语言上机真题
  16. CMSIS Driver
  17. android ntp服务器配置
  18. 定时执行Python程式
  19. Linux CentOS安装增强功能--完整版命令
  20. Docker和Pycharm

热门文章

  1. ITK:减去两个图像
  2. ITK:使图像的一部分透明化
  3. ITK:概念检查是浮点数
  4. QML资源加载和网络透明度
  5. C++Quick sort快速排序的实现算法之二(附完整源码)
  6. QT的QMutexLocker类的使用
  7. QT的QGraphicsItemGroup类的使用
  8. 经典C语言程序100例之四七
  9. C++ inline内联函数
  10. vue require动态路径图片报错_Vue 动态生成路由结构