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
原文地址:http://www.cnblogs.com/stevenczp/p/7597903.html