Netty源码学习(五)ChannelInitializer
0. ChannelInitializer简介
直接用ChannelInitializer的注释吧:A special ChannelInboundHandler which offers an easy way to initialize a Channel once it was registered to its eventLoop.
1. ChannelInitializer类图

需要注意的是:
a. ChannelInitializer继承于ChannelInboundHandler接口
b. ChannelInitializer是一个抽象类,不能直接使用
2. initChannel抽象方法
ChannelInitializer中声明了一个名为initChannel的抽象方法:
/**
* This method will be called once the {@link Channel} was registered. After the method returns this instance
* will be removed from the {@link ChannelPipeline} of the {@link Channel}.
*
* @param ch the {@link Channel} which was registered.
* @throws Exception is thrown if an error occurs. In that case it will be handled by
* {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
* the {@link Channel}.
*/
protected abstract void initChannel(C ch) throws Exception;
ChannelInitializer的实现类必须要重写这个方法,这个方法在Channel被注册到EventLoop的时候会被调用
3. ChannelInitializer什么时候会被调用?
以ServerBootstrap启动这一场景为例
在ServerBootstrap.init()方法中,负责accept新链接的Channel的pipeline被添加了一个ChannelInitializer
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
由于此时这个Channel还没有被register到EventLoop,于是在addLast方法的调用链中,会给pipeline添加一个PendingHandlerAddedTask,其目的是在Channel被register到EventLoop的时候,触发一个回调事件
然后在AbstractBootstrap.initAndRegister()方法中,这个Channel会被register到boss EventLoopGoup,接着会被register到boss EventLoopGoup中的某一个具体的EventLoop
在AbstractChannel.register0()方法中,之前注册的PendingHandlerAddedTask会被调用,经过一系列调用之后,ChannelInitializer.handleAdded()方法会被触发:
/**
* {@inheritDoc} If override this method ensure you call super!
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
// This should always be true with our current DefaultChannelPipeline implementation.
// The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
// surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
// will be added in the expected order.
initChannel(ctx);
}
} @SuppressWarnings("unchecked")
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
try {
initChannel((C) ctx.channel());//调用子类重写的initChannel方法
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
remove(ctx);//将ChannelInitializer从pipeline中移除
}
return true;
}
return false;
} /**
* This method will be called once the {@link Channel} was registered. After the method returns this instance
* will be removed from the {@link ChannelPipeline} of the {@link Channel}.
*
* @param ch the {@link Channel} which was registered.
* @throws Exception is thrown if an error occurs. In that case it will be handled by
* {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
* the {@link Channel}.
*/
protected abstract void initChannel(C ch) throws Exception; private void remove(ChannelHandlerContext ctx) {
try {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
} finally {
initMap.remove(ctx);
}
}
大概意思是:
a. 触发ChannelInitializer的initChannel方法,执行子类定义的一系列操作(在ServerBootstrap这个例子中就是将ServerBootstrapAcceptor注册到pipeline中)
b. 将ChannelInitializer从pipeline中移除
4. 总结
ChannelInitializer的主要目的是为程序员提供了一个简单的工具,用于在某个Channel注册到EventLoop后,对这个Channel执行一些初始化操作。ChannelInitializer虽然会在一开始会被注册到Channel相关的pipeline里,但是在初始化完成之后,ChannelInitializer会将自己从pipeline中移除,不会影响后续的操作。
使用场景:
a. 在ServerBootstrap初始化时,为监听端口accept事件的Channel添加ServerBootstrapAcceptor
b. 在有新链接进入时,为监听客户端read/write事件的Channel添加用户自定义的ChannelHandler
Netty源码学习(五)ChannelInitializer的更多相关文章
- 【Netty源码学习】ServerBootStrap
上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...
- Netty 源码学习——客户端流程分析
Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...
- Netty源码学习系列之4-ServerBootstrap的bind方法
前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...
- 【Netty源码学习】DefaultChannelPipeline(三)
上一篇博客中[Netty源码学习]ChannelPipeline(二)我们介绍了接口ChannelPipeline的提供的方法,接下来我们分析一下其实现类DefaultChannelPipeline具 ...
- 【Netty源码学习】ChannelPipeline(一)
ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...
- Netty 源码学习——EventLoop
Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...
- 【Netty源码学习】EventLoopGroup
在上一篇博客[Netty源码解析]入门示例中我们介绍了一个Netty入门的示例代码,接下来的博客我们会分析一下整个demo工程运行过程的运行机制. 无论在Netty应用的客户端还是服务端都首先会初始化 ...
- (一)Netty源码学习笔记之概念解读
尊重原创,转载注明出处,原文地址:http://www.cnblogs.com/cishengchongyan/p/6121065.html 博主最近在做网络相关的项目,因此有契机学习netty,先 ...
- netty源码学习
概述 Netty is an asynchronous event-driven network application framework for rapid development of main ...
- Netty源码学习(六)ChannelPipeline
0. ChannelPipeline简介 ChannelPipeline = Channel + Pipeline,也就是说首先它与Channel绑定,然后它是起到类似于管道的作用:字节流在Chann ...
随机推荐
- 如何使用API创建OpenStack虚拟机?
在安装时OpenStack会加载配置信息.有不同的虚拟机模板而且与在Amazon EC2以及其他平台上看到的完全一样.这些配置是内存.vCPU.磁盘容量等的组合,定义了虚拟机的大小及容量.可以使用如下 ...
- Python全栈工程师(元组、字典)
ParisGabriel 感谢 大家的支持 你们的阅读评价就是我最好的更新动力 我会坚持吧排版做的越来越好 每天坚持 一天一篇 点个订阅吧 灰常感谢 当个死粉也阔以 ...
- 孤荷凌寒自学python第二十三天python类的封装
孤荷凌寒自学python第二十三天python类的封装 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.从怎么样访问类的内部代码块中定义的私有属性说起 类中定义的私有属性和私有方法是无法被 ...
- 解决windows文件名过长无法删除的问题
删除windows文件时,系统提示如下错误: 从网上找到下面的一种方法,顺利解决(原理不清楚),现记录删除方法如下: . 在要删除的文件夹(delete_dir)同级新建一个空文件夹(empty_di ...
- iPhone新建项目不能全屏
上个周做项目的时候,发现新建了一个项目不能全屏.伤透了我的脑筋,然后又请教了团队里其他两个大牛帮我搞定了这个问题. 虽然是搞定了,但也看的出大牛也是云里雾里.歪打正着解决的. 今天又想新做个项目,这个 ...
- hdu 2492 树状数组 Ping pong
欢迎参加——BestCoder周年纪念赛(高质量题目+多重奖励) Ping pong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 3 ...
- SVN基本介绍
SVN是一种项目合作开发的软件,参与项目的人员可以在不同的地方实现文件和目录的超时空共享. 两个重要的概念: 1.配置库(Repository) SVN的核心是配置库,储存所有的数据,配置库按照文件树 ...
- Java进行身份证格式强校验(准)
最近做了一个系统,涉及到对用户输入的身份证号进行校验,减少脏数据传入后台处理并降低企业验证成本,因此在接入层便对输入信息做格式强校验. 直接附上代码,可直接使用. package hope.ident ...
- 解决IE浏览器中出现“Resource interpreted as Document but transferred with MIME type application/json”问题
在上传图片时,使用ajax提交,返回的数据格式为json.在测试时发现IE浏览器中,上传图片后,没有显示图片,而是弹出一个提示:是否保存UploadImg.json文件:而在其他浏览器中正常. 在Ch ...
- VMware 密匙
11.0版本 1F04Z-6D111-7Z029-AV0Q4-3AEH8 亲测可用