分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 代码编程

Netty源码学习(五)ChannelInitializer

发布时间:2023-09-06 01:14责任编辑:沈小雨关键词:暂无标签

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

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved