Netty服务端启动过程相关源码分析
1、Netty 是怎么创建服务端Channel的呢?
我们在使用ServerBootstrap.bind(端口)方法时,最终调用其父类AbstractBootstrap中的doBind方法,相关源码如下:
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化和注册
final ChannelFuture regFuture = initAndRegister();
.....
我们继续跟进initAndRegister()这个方法,发现是使用channelFactory.newChannel() 完成channel的创建:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {......}
ChannelFactory在实现类ReflectiveChannelFactory中的实现细节,内部使用了反射的方式创建Channel:
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {......}
}
这里的ChannelFactory是通过 bootstrap.channel(NioServerSocketChannel.class) 加入的:
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
- 综上所述,Netty就是调用jdk底层方法创建NIO的channel,也就是通过反射完成NIO的channel创建。最后其包装成Netty自己的Channel.
2、初始化服务端Channel是怎么样的执行流程?
在创建了Channel之后就调用AbstractBootstrap的init(channel)抽象方法完成初始化:
abstract void init(Channel channel) throws Exception;
服务器端ServerBootstrap的init方法从源码来看主要完成工作为:
- 配置相关的Options和Attribute。
- 通过ChannelPipeline 添加相关逻辑处理器 ChannelHandler。
最后这些属性会传入ServerBootstrapAcceptor连接器,通过ServerBootstrapAcceptor连接器完成相应的初始化。
// We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
// In this case the initChannel(...) method will only be called after this method returns. Because
// of this we need to ensure we add our handler in a delayed fashion so all the users handler are
// placed in front of the ServerBootstrapAcceptor.
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
3、怎么注册selector?
在Java NIO 中注册通道Channel到多路复用器Selector,并说明关注点SelectionKey.OP_ACCEPT,监听ACCEPT事件通常我们会这样写:
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
Netty在底层将Channel注册到事件轮询器selector上就是基于此方法:
- 首先在初始化Channel后执行:
ChannelFuture regFuture = config().group().register(channel);
上面的代码实际是调用AbstractChannel的register方法,完成eventLoop的绑定。内部方法register0()中会调用AbstractNioChannel的doRegister() 方法:
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return;
} catch (CancelledKeyException e) {......}
}
}
这里其实就是调用NIO SelectableChannel的register方法。
- 从源码可以知道,注册成功后这里会以此执行服务器handler中的回调方法:handlerAdded ,channelActive
4、端口怎么绑定呢?
一切OK之后就会调用AbstractChannel中的 bind 方法,这个方法又会调用NioServerSocketChannel 的 doBind 方法,从doBind方法可知是调用的原生NIO 的bind做绑定:
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
绑定完成后会执行代码:
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
这里会调用DefaultChannelPipeline中的内部类HeadContext的channelActive方法进行事件传播:
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();
}
那么服务端到底是在哪里 accept 连接的呢?
通过上面的代码我们跟进 AbstractChannel 的beginRead() 方法,继而找到 AbstractNioChannel 的 doBeginRead() 方法:
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
上面的代码就是NIO编程中常用的写法,这里监听ACCEPT事件就是NioServerSocketChannel构造函数调用父类传入的SelectionKey.OP_ACCEPT:
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
Netty服务端启动过程相关源码分析的更多相关文章
- Netty 服务端启动过程
在 Netty 中创建 1 个 NioServerSocketChannel 在指定的端口监听客户端连接,这个过程主要有以下 个步骤: 创建 NioServerSocketChannel 初始化并注 ...
- Kafka服务端之网络连接源码分析
#### 简介 上次我们通过分析KafkaProducer的源码了解了生产端的主要流程,今天学习下服务端的网络层主要做了什么,先看下 KafkaServer的整体架构图 
首先,整理NIO进行服务端开发的步骤: (1)创建ServerSocketChannel,配置它为非阻塞模式. (2)绑定监听,配置TCP参数,backlog的大小. (3)创建一个独立的I/O线程, ...
- spring mvc 启动过程及源码分析
由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...
- Netty源码解析 -- 服务端启动过程
本文通过阅读Netty源码,解析Netty服务端启动过程. 源码分析基于Netty 4.1 Netty是一个高性能的网络通信框架,支持NIO,OIO等多种IO模式.通常,我们都是使用NIO模式,该系列 ...
- Netty之旅三:Netty服务端启动源码分析,一梭子带走!
Netty服务端启动流程源码分析 前记 哈喽,自从上篇<Netty之旅二:口口相传的高性能Netty到底是什么?>后,迟迟两周才开启今天的Netty源码系列.源码分析的第一篇文章,下一篇我 ...
- netty服务端启动--ServerBootstrap源码解析
netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...
- Netty 学习(五):服务端启动核心流程源码说明
Netty 学习(五):服务端启动核心流程源码说明 作者: Grey 原文地址: 博客园:Netty 学习(五):服务端启动核心流程源码说明 CSDN:Netty 学习(五):服务端启动核心流程源码说 ...
- SpringCloud微服务如何优雅停机及源码分析
目录 方式一:kill -9 java进程id[不建议] 方式二:kill -15 java进程id 或 直接使用/shutdown 端点[不建议] kill 与/shutdown 的含义 Sprin ...
随机推荐
- MyBatis从入门到精通(六):MyBatis动态Sql之if标签的用法
最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解如何使用if标签生成动 ...
- 2018.8.19 2018暑假集训之maxnum
昨天去做志愿服务去了没写成Q_Q 今天再来一道 先放题面描述 设有n个正整数(n<=20),将它们联成一排,组成一个最大的多位数 设有n个正整数(n<=20),将它们联成一排,组成一个最大 ...
- XTOJ 1267:Highway(树的直径)***
http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1267 题意:给出一棵树,每条树边有权值,现在要修建n-1条边,边的权值为边 ...
- .NET CORE上传文件到码云仓库【搭建自己的图床】
.NET CORE上传文件到码云仓库[搭建自己的图床] 先建一个公共仓库(随意提交一个README文件或者.gitignore文件保证master分支的存在),然后到gitee的个人设置页面找到[私人 ...
- 【弱化版】【P3371 【模板】单源最短路径(弱化版)】-C++
→原题传送门← 看到题目描述我就知道,这道题不能用SPFA[手动补滑稽] 那么我这道题目采用的是dijkstra算法不了解的去补一下知识哈. dij的模板: #include<bits/stdc ...
- youku_androidid
youku_androidid = 1310; imei screenwidth screenhight
- vs调试看窗口风格
vs调试看窗口风格 技巧:在数值上右键,以16进制显示.
- 【Go】类似csv的数据日志组件设计
原文链接:https://blog.thinkeridea.com/201907/go/csv_like_data_logs.html 我们业务每天需要记录大量的日志数据,且这些数据十分重要,它们是公 ...
- HelloDjango 启动!免费带你学Django全栈!
欢迎 追梦 入伙 HelloGitHub-Team,同时为我们带来了完全免费的 HelloDjango 系列教程,全网首发于 HelloGitHub 公众号.让想你的系列文章被跟多人看到,那就来加入我 ...
- SpringBoot2.0集成WebSocket,实现后台向前端推送信息
感谢作者,支持原创: https://blog.csdn.net/moshowgame/article/details/80275084 什么是WebSocket? WebSocket协议是基于TCP ...