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的更多相关文章

  1. 【Netty源码学习】ServerBootStrap

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

  2. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

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

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

  4. 【Netty源码学习】DefaultChannelPipeline(三)

    上一篇博客中[Netty源码学习]ChannelPipeline(二)我们介绍了接口ChannelPipeline的提供的方法,接下来我们分析一下其实现类DefaultChannelPipeline具 ...

  5. 【Netty源码学习】ChannelPipeline(一)

    ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...

  6. Netty 源码学习——EventLoop

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

  7. 【Netty源码学习】EventLoopGroup

    在上一篇博客[Netty源码解析]入门示例中我们介绍了一个Netty入门的示例代码,接下来的博客我们会分析一下整个demo工程运行过程的运行机制. 无论在Netty应用的客户端还是服务端都首先会初始化 ...

  8. (一)Netty源码学习笔记之概念解读

    尊重原创,转载注明出处,原文地址:http://www.cnblogs.com/cishengchongyan/p/6121065.html  博主最近在做网络相关的项目,因此有契机学习netty,先 ...

  9. netty源码学习

    概述 Netty is an asynchronous event-driven network application framework for rapid development of main ...

  10. Netty源码学习(六)ChannelPipeline

    0. ChannelPipeline简介 ChannelPipeline = Channel + Pipeline,也就是说首先它与Channel绑定,然后它是起到类似于管道的作用:字节流在Chann ...

随机推荐

  1. C# p-Inovke C++动态链接库

    在C++的动态链接库 写了一个测试方法,然后想在C#客户端进行pInvoke调用,始终报异常如下: 试图加载格式不正确的程序. (异常来自 HRESULT:0x8007000B). 最后发现, 需要将 ...

  2. Java 注解(Annoation)学习笔记

    1 Junit中的@Test为例: 1.1 用注解(@Test)前 private boolean isTestMethod(Method m) { return m.getParameterType ...

  3. Java基础-3类和对象声明与创建

    一).在1和2中有粗略介绍过类和对象的概念,在这里简单回顾一下: 对象与类:一个实际或者虚拟的物体,这个物体既是我们的对象,这个物体呢又是属于一个分类,如动物类,人类 二).创建对象: 在创建对象的时 ...

  4. 《大道至简》第一章 编程的精义 java伪代码形式

    愚公.这位名家身上,浓缩了项目组织者.团队经理.编程人员.技术分析师等众多角色的优秀素质. 愚公移山事件分析: 原始需求:惩山北之塞,出入之迂 项目沟通方式:聚室而某曰 项目目标:毕力平险,指通豫南, ...

  5. Could not automatically select an Xcode project. Specify one in your Podfile like so

    需要将Podfile文件放置在根目录下,而不能放置在项目的里面. 更改路径即可

  6. CodeForces B. Creating the Contest

    http://codeforces.com/contest/1029/problem/B You are given a problemset consisting of nn problems. T ...

  7. Apache2.4启动时报AH00526错误(Invalid command 'Order')

    在WIN XP下手动配置PHP环境,安装Apache2.4+fastcgi后,重启Apache服务,出现如下提示: AH00526: Syntax error on line 293 of D:/ph ...

  8. swipe display: none后再显示,加载内容后,滑动失效问题

    只需要添加这两个属性即可: observer:true,//修改swiper自己或子元素时,自动初始化swiper observeParents:true//修改swiper的父元素时,自动初始化sw ...

  9. 论文笔记《Deep Hand: How to Train a CNN on 1 Million Hand Images When Your Data Is Continuous and Weakly Labelled》

    一.概述 这个是最近的核心工作了,基本上都是靠着这篇paper的model过日子了啊.. 论文主要讲的是hand gesture recognition,实际上是用googlenet做的一个class ...

  10. 7月9日day1总结

    今天的学习过程和小结 上午学习了前端包括html,CSS,js等基本内容 前端10.25.134.187 html js css 1.块元素 ---默认占满整行,如果设置了高度和宽度都有效,如果不设置 ...