• Outbound事件是请求事件。
  • Outbound事件的发起者是Channel,处理者是Unsafe。
  • Outbound事件在Pipeline中传输方向是tail -> head。

Outbount事件其中之一bind,以bind为例:
AbstractChannel
bind(SocketAddress localAddress, ChannelPromise promise):

@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {return pipeline.bind(localAddress, promise);
}
  1. 该方法实现自ChannelOutboundInvoker接口。
  2. 方法内部调用被被bind(SocketAddress localAddress, ChannelPromise promise) 方法。

看bind(SocketAddress localAddress, ChannelPromise promise) 方法的具体实现:

@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {return tail.bind(localAddress, promise);
}
    @Overridepublic ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {if (localAddress == null) {throw new NullPointerException("localAddress");}// 判断 Promise 对象是否合法。if (isNotValidPromise(promise, false)) {// cancelledreturn promise;}// 获得下一个 Outbound 节点final AbstractChannelHandlerContext next = findContextOutbound();// 获得下一个 Outbound 节点的执行器EventExecutor executor = next.executor();// 调用下一个 Outbound 节点的 bind 方法if (executor.inEventLoop()) {next.invokeBind(localAddress, promise);} else {safeExecute(executor, new Runnable() {@Overridepublic void run() {next.invokeBind(localAddress, promise);}}, promise, null);}return promise;}

上面判断promise对象是否合法,isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise)

private boolean isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise) {if (promise == null) {throw new NullPointerException("promise");}// Promise 已经完成if (promise.isDone()) {// Check if the promise was cancelled and if so signal that the processing of the operation// should not be performed.//// See https://github.com/netty/netty/issues/2349if (promise.isCancelled()) {return true;}throw new IllegalArgumentException("promise already done: " + promise);}// Channel 不符合if (promise.channel() != channel()) {throw new IllegalArgumentException(String.format("promise.channel does not match: %s (expected: %s)", promise.channel(), channel()));}// DefaultChannelPromise 合法 if (promise.getClass() == DefaultChannelPromise.class) {return false;}// 禁止 VoidChannelPromise if (!allowVoidPromise && promise instanceof VoidChannelPromise) {throw new IllegalArgumentException(StringUtil.simpleClassName(VoidChannelPromise.class) + " not allowed for this operation");}// 禁止 CloseFutureif (promise instanceof AbstractChannel.CloseFuture) {throw new IllegalArgumentException(StringUtil.simpleClassName(AbstractChannel.CloseFuture.class) + " not allowed in a pipeline");}return false;
}

关于调用findContextOutbound()方法,获得下一个Outbound节点:
注意从pipeline的tail->head。

private AbstractChannelHandlerContext findContextOutbound() {// 循环,向前获得一个 Outbound 节点AbstractChannelHandlerContext ctx = this;do {ctx = ctx.prev;} while (!ctx.outbound);return ctx;
}

调用 AbstractChannelHandlerContext#executor() 方法,获得下一个Outbound节点的执行器:
如果未设置子执行器,则Channel的EventLoop作为执行器。

// Will be set to null if no child executor should be used, otherwise it will be set to the
// child executor.// EventExecutor 对象final EventExecutor executor;@Override
public EventExecutor executor() {if (executor == null) {return channel().eventLoop();} else {return executor;}
}
  • 如果在EventLoop的线程中,那么调用下一个节点的invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法,传播 bind 事件给下一个节点。
  • 如果不在EventLoop线程中,调用safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg)方法,提交到EventLoop的线程中执行:
private static void safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg) {try {// 提交到 EventLoop 的线程中,进行执行任务executor.execute(runnable);} catch (Throwable cause) {try {// 发生异常,回调通知 promise 相关的异常promise.setFailure(cause);} finally {// 释放 msg 相关的资源if (msg != null) {ReferenceCountUtil.release(msg);}}}
}

invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法:

 private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {if (invokeHandler()) { // 判断是否符合的 ChannelHandler// 如果是不符合的ChannelHandler,则跳过该节点。try {// 调用该 ChannelHandler 的 bind 方法((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);} catch (Throwable t) {notifyOutboundHandlerException(t, promise); // 通知 Outbound 事件的传播,发生异常}} else {// 跳过,传播 Outbound 事件给下一个节点bind(localAddress, promise);}}

上面调用InvokeHandler()方法,判断是否是符合的ChannelHandler:

/*** Makes best possible effort to detect if {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called* yet. If not return {@code false} and if called or could not detect return {@code true}.** If this method returns {@code false} we will not invoke the {@link ChannelHandler} but just forward the event.* This is needed as {@link DefaultChannelPipeline} may already put the {@link ChannelHandler} in the linked-list* but not called {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}.*/
private boolean invokeHandler() {// Store in local variable to reduce volatile reads.int handlerState = this.handlerState;return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
}

这里。ordered = true的节点,必须与ChannelHandler已添加完毕。
ordered = false的节点,没有ChannelHandler的要求。
bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) 方法:

@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {unsafe.bind(localAddress, promise);
}

unsafe进行处理。说明Unsafe是bind的处理者。


  • Inbound事件是通知事件。
  • Inbound事件发起者是Unsafe,处理者是TailContext。
  • Inbound事件在Pipeline中传输方向是head -> tail。

Inbound和Outbound很相似,镜像。俺就不说啦。

Netty之ChannelPipeline(三)Outbound与Inbound事件的传播相关推荐

  1. Netty核心组件 ChannelPipeline和ChannelHandler与ChannelHandler的入站出站规则

    概述 Netty中ChannelPipeline与Channel的对应关系是一一对应,也就是每个Channel中有且仅有一个ChannelPipeline,可以通过Channel获取唯一的Channe ...

  2. NIO与Netty编程(三)之Netty编程

    1.概述 Netty是JBOSS提供的一个Java开源框架.Netty提供异步的,基于事件驱动的网络应用程序框架,用以快速开发高性能.高可靠性的网络IO程序. Netty是一个基于NIO的网络编程框架 ...

  3. Netty 简单服务器 (三)

    2019独角兽企业重金招聘Python工程师标准>>> 经过对Netty的基础认识,设计模型的初步了解,来写个测试,试试手感 上篇也说到官方推荐我们使用主从线程池模型,那就选择这个模 ...

  4. 用仿ActionScript的语法来编写html5——第三篇,鼠标事件与游戏人物移动

    第三篇,鼠标事件与游戏人物移动 一,假设 假设,所有可添加鼠标事件的对象,都有一个mouseEvent方法,添加的鼠标事件同过这个mouseEvent来调用. 这样的话,添加鼠标事件,其实只需要给ca ...

  5. JavaScript学习(三十四)—事件委托

    JavaScript学习(三十四)-事件委托 (一).什么是事件委托? 所谓的事件委托就是指将事件添加到祖先元素身上,依据事件冒泡的原理(就是指事件的执行顺序是从当前元素逐步扩展到祖先元素,直到扩展到 ...

  6. html游戏让目标人物移动,用仿ActionScript的语法来编写html5——第三篇,鼠标事件与游戏人物移动...

    第三篇,鼠标事件与游戏人物移动 一,假设 假设,所有可添加鼠标事件的对象,都有一个mouseEvent方法,添加的鼠标事件同过这个mouseEvent来调用. 这样的话,添加鼠标事件,其实只需要给ca ...

  7. Elastic-job系列(三)-------- 控制台作业事件追踪TODO

    一.简介 esjob提供了任务事件追踪功能,通过做数据源配置,监听事件,会在任务执行的时候在指定的数据源创建俩张表,job_execution_log, 和 job_status_trace_log. ...

  8. 【Vue教程三】点击事件、表单输入事件、键盘事件

    一.点击事件: 1.可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码. 'v-on:click' 简写成 '@click' <body><di ...

  9. 13前端学习之WebAPI(三):节点操作、事件高级、DOM事件流、事件委托冒泡

    文章目录 一.节点操作: 1. 删除节点: 1.2. 案例:删除留言 2. 赋值(克隆)节点: 3. 案例:动态生成表格: 3.1 案例分析: 3.2 实现: 4. 创建元素的三种方式: 4.1 区别 ...

最新文章

  1. android+ip+rule+策略路由,策略路由以及使用 ip route , ip rule , iptables 配置策略路由实例...
  2. 服务机器人平台和后台
  3. 大数据促健康产业高增长
  4. AMD和CMD出生的背景和它们解决的问题
  5. Teams与OneDrive for Business和SharePoint的关系
  6. nginx php iconv,Nginx +PHP部署一
  7. 贪心算法(leetcode分类解题,C++代码详细注释)
  8. 【实用数学手册(第2版)扫描版.pdf】和【免安装Matlab.7.0.绿色破解U盘便携移...】 百度网盘下载地址
  9. 百度原创度在线检测_资深自媒体作者:做自媒体没有这款“原创度检测”软件是不行的...
  10. 万字长文!用文本挖掘深度剖析54万首诗歌
  11. 树莓派制作游戏机教程
  12. 云呐|固定资产管理的目的,固定资产管理办法的目的
  13. 数据结构之三元组的实现
  14. 区块链知识系列 - 系统学习EVM(二)-存储与安全
  15. Istio,下一个Kubernetes?
  16. Tensorflow安装过程的一些问题及解决办法
  17. 爬虫的智能化解析之使用Diffbot自动解析页面
  18. 教育知识与能力必背简答题!
  19. Java连接MySQL数据库并进行简单查询
  20. CSDN:2018年度CSDN博客之星评选竞赛——094号,感谢您,投上的宝贵一票,感谢!感恩!

热门文章

  1. 看完此帖你100%会感动的流泪[感动]
  2. python 求解x=tanx方程
  3. HDU1430 魔板 康托展开
  4. bugku-writeup-MISC-赛博朋克
  5. 什么是“长连接”和“短连接”?
  6. 第2节 网络及IP地址详解
  7. 处理顶点——凹凸映射:固定法线
  8. 开源php ugc 社区,如何设计UGC社区的内容展示规则?
  9. java jackson maven_jackson系列(一)_基本使用
  10. 复试21天Day 17