状态 | 描述 |
---|---|
ChannelUnregistered | Channel已经被建立,但未注册到EventLoop |
ChannelRegistered | Channel已经被注册到了EventLoop |
ChannelActive | Channel处于活动状态(已经链接到它的远程节点)。如今Channel能够接受和发送数据 |
ChannelInActive | Channel没有链接到远程节点 |
通常Channel的生命周期顺序ChannelRegistered -> ChannelActive -> ChannelInactive -> ChannelUnregistered。java
当Channel的状态发生变化时,将会生成对应的事件。与此同时,这些事件会被转发给ChannelPipeline中的ChannelHandler。缓存
ChannelHandler定义的生命周期操做,在ChannelHandler被添加到ChannelPipeline中或者被从ChannelPipeline中移除时会调用这些方法。这些方法中均可以接受一个ChannelHandlerContext参数。安全
类型 | 描述 |
---|---|
handlerAdded | 当把ChannelHandler添加到ChannelPipeline中时被调用 |
handlerRemoved | 当从ChannelHandler在ChannelPipeline移除时调用 |
exceptionCaught | 当处理过程当中在ChannelPipeline中有错误产生时被调用 |
Netty中定义了下面两个重要的ChannelHandler接口:并发
类型 | 描述 |
---|---|
channelRegistered | 当Channel已经注册到它的EventLoop而且可以处理I/O时被调用 |
channelUnregistered | 当Channel从它的EventLoop注销而且没法处理任何I/O时被调用 |
channelActive | 当Channel处于活动状态时被调用;Channel已经链接/绑定而且已经就绪 |
channelInactive | 当Channel离开活动状态而且再也不链接它的远程节点时被调用 |
channelReadComplete | 当Channel的一个读操做完成时被调用 |
channelRead | 当从Channel读取数据时被调用 |
channelWritabilityChanged | 当Channel的可写状态发生改变时被调用。用户能够确保写操做不会完成的太快(以免发生OutOfMemoryError)或者能够在Channel变为再次可写时恢复写入。Channel的isWriteable()方法能够来检测Channel的可写性。与可写性相关的阀值能够经过Channel.config().setWriteHighWaterMark()和Channel.config().setWriteLowWaterMark()方法来设置 |
userEventTriggered | 当ChannelInboundHandler.fireUserEventTriggered()方法被调用时被调用。 |
当某个ChannelInboundHandler的实现重写channelRead()方法时,它将负责显示地释放与池化的ByteBuf实例相关的内存。ReferenceCountUtil.release()异步
Netty会使用WARN级别的日志消息记录未释放的资源,可是以这种方式管理资源可能很是繁琐,Netty采用SimpleChannelInboundHandler来简化这种操做。oop
出站操做和数据将由ChannelOutboundHandler处理。它的方法将被Channel、ChannelPipeline以及ChannelHandlerContext调用。布局
ChannelOutboundHandler能够按需推迟操做或者事件。性能
类型 | 描述 |
---|---|
bind(ChannelHandlerContext, SockertAddress, ChannelPromise) | 当请求将Channel绑定到本地地址时被调用 |
connect(ChannelHandlerContext, SocketAddress, SockertAddress, ChannelPromise) | 当请求将Channel链接到远程节点时被调用 |
disconnect(ChannelHandlerContext, ChannelPromise) | 当请求将Channel从远程节点断开时被调用 |
close(ChannelHandlerContext, ChannelPromise) | 当请求关闭Channel时被调用 |
deregister(ChannelHandlerContext, ChannelPromise) | 当请求将Channel丛它的EventLoop注销时被调用 |
read(ChannelHandlerContext) | 当请求从Channel读取更多的数据时被调用 |
flush(ChannelHandlerContext) | 当请求经过Channel将入队数据冲刷到远程节点时被调用 |
write(ChannelHandlerContext, Object, ChannelPromise) | 当请求经过Channel将数据写到远程节点时被调用 |
ChannelOutboundHandler中的大部分方法都须要一个ChannelPromise参数,方便在操做完成时获取通知。ChannelPromise时ChannelFuture的一个子类,定义了一些可写方法,如setSuccess()和setFailure()方法测试
ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter两个适配器分别提供了ChannelInboundHandler和ChannelOutboundHandler的基本实现。经过扩展抽象类ChannelHandlerAdapter,它们得到了它们共同的超接口ChannelHandler的方法。spa
ChannelHandlerAdapter提供了isSharable(),若是其对应的实现被注解标注为Sharable,这方法将返回true,表示它能够被添加到多个ChannelPipeline。
ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter中的方法体调用了其相关联的ChannelHandlerContext上的等效方法,从而将事件转发到了ChannelPipeline中的下一个ChannelHandler中。
Netty目前定义了4种泄露检测级别:
级别 | 描述 |
---|---|
DISABLED | 禁用泄漏检测。只有在详尽的测试以后才应设置为这值 |
SIMPLE | 使用1%的默认采样率检测并报告任何发现的泄漏。这是默认级别,适合绝大部分状况 |
ADVANCED | 使用默认的采样率,报告所发现的任何的泄漏以及对应的消息被访问的位置 |
PARANOID | 相似于ADVANCED,可是其将会对每次(对消息的)访问都进行采样。会对性能有很大影响,只能在调试阶段使用 |
java -Dio.netty.leakDetectionLevel=ADVANCED
若是一个消息被消费或者丢弃了,而且没有传递给ChannelPipeline中的下一个ChannelOutboundHandler,那么用户就有责任调用ReferenceCountUtil.release()。若是消息到达了实际的传输层,那么当它被写入时或者Channel关闭时,都将被自动释放。
每个新建立的Channel都将会被分配一个新的ChannelPipeline。这项关联是永久性的;Channel既不能附加另一个ChannelPipeline,也不能分离当前的。
根据事件的起源,事件将会被ChannelInboundHandler或者ChannelOutboundHandler处理。随后,会调用ChannelHandlerContext实现,它将被转发给同一超类型的下一个ChannelHandler。
ChannelHandlerContext使ChannelHandler可以和它的ChannelPipeline以及其余的ChannelHandler交互。ChannelHandler能够通知其所属的ChannelPipeline中的下一个ChannelHandler,甚至能够动态修改它所属的ChannelPipeline。
在ChannelPipeline传播事件时,它会测试ChannelPipeline中的下一个ChannelHandler的类型是否和事件的运动方向相匹配。若是不匹配,ChannelPipeline将跳过该ChannelHandler并前进到下一个,直到它找到和该事件所指望的方向相匹配的为止。(ChannelHandler能够同时实现ChannelInboundHandler和ChannelOutboundHandler接口)
ChannelHandler能够经过添加、删除或者替换其余的ChannelHandler来实时地修改ChannelPipeline的布局。
名称 | 描述 |
---|---|
addFirst(),addBefore(),addAfter(),addLast() | 将一个ChannelHandler添加到ChannelPipeline |
remove() | 将一个ChannelHandler从ChannelPipeline中移除 |
replace() | 将ChannelPipeline中的一个ChannelHandler替换为另外一个ChannelHandler |
get() | 经过类型或者名称返回ChannelHandler |
context() | 返回和ChannelHandler绑定的ChannelHandlerContext |
names() | 返回ChannelPipeline中全部的ChannelHandle的名称 |
ChannelPipeline的API公开了用于调用入站和出站操做的附加方法,用于通知ChannelInboundHandler在ChannelPipeline中所发生的事件。
名称 | 描述 |
---|---|
fireChannelRegistered | 调用ChannelPipeline中下一个ChannelInboundHandler的channelRegistered(ChannelHandlerContext)方法 |
fireChannelUnregistered | 调用ChannelPipeline中下一个ChannelInboundHandler的channelUnregistered(ChannelHandlerContext)方法 |
fireChannelActive | 调用ChannelPipeline中下一个ChannelInboundHandler的channelActive(ChannelHandlerContext) |
fireChannelInActive | 调用ChannelPipeline中下一个ChannelInboundHandler的channelInactive(ChannelHandlerContext)方法 |
fireExceptionCaught | 调用ChannelPipeline中下一个ChannelInboundHandler的exceptionCaught(ChannelHandlertext, Throwable)方法 |
fireUserEventTriggerd | 调用ChannelPipeline中下一个ChannelInboundHandler的userEventTriggered(ChannelHandlertext, Object)方法 |
fireChannelRead | 调用ChannelPipeline中下一个ChannelInboundHandler的channelRead(ChannelHandlertext, Object msg)方法 |
fireChannelReadComplete | 调用ChannelPipeline中下一个ChannelInboundHandler的channelReadComplete(ChannelHandlertext)方法 |
fireChannelWritabilityChanged | 调用ChannelPipeline中下一个ChannelInboundHandler的channelWritabilityChanged(ChannelHandlertext)方法 |
ChannelPipelin的出站操做
名称 | 描述 |
---|---|
bind | 将Channel绑定到一个本地地址,将调用ChannelPipeline中的下一个ChannelOutboundHandler的bind(ChannelHandlerContext,Socket,ChannelPromise)方法 |
connect | 将Channel链接到一个远程地址,这将调用ChannelPipeline中的下一个ChannelOutboundHandler的connect(ChannelHandlerContext,Socket,ChannelPromise)方法 |
disconnect | 将Channel断开链接。这将调用ChannelPipeline中的下一个ChannelOutboundHandler的disconnect(ChannelHandlerContext,Socket,ChannelPromise)方法 |
close | 将Channel关闭。这将调用ChannelPipeline中的下一个ChannelOutboundHandler的close(ChannelHandlerContext,ChannelPromise)方法 |
deregister | 将Channel从它先前分配的EventExecutor(即EventLoop)中注销,这将调用ChannelPipeline中的下一个ChannelOutboundHandler的deregister(ChannelHandlerContext,ChannelPromise)方法 |
flush | 冲刷Channel全部挂起的写入。这将调用ChannelPipeline中的下一个ChannelOutboundHandler的flush(ChannelHandlerContext)方法 |
write | 将消息写入Channel。这将调用ChannelPipeline中的下一个ChannelOutboundHandler的write(ChannelContext,Object msg,ChannelPromise)方法。这并不会将消息写入底层的Socket,而只会将它放入到队列中。要将它写入到Socket,须要调用flush或者writeAndFlush方法 |
writeAndFlush | 先调用write再调用flush的便利方法 |
read | 请求从Channel中读取更多的数据。这将调用ChannelPipeline中的下一个ChannelOutboundHandler的read(ChannelHandlerContext)方法 |
ChannelHandlerContext表明了ChannelHandler和ChannelPipeline之间的关联。每当有ChannelHandler添加到ChannelPipeline中时,都会建立ChannelHandlerContext。ChannelHandlerContext的主要功能是管理它所关联的ChannelHandler和在同一个ChannelPipeline中的其余ChannelHandler之间的交互。
ChannelHandlerContext有不少方法,其中一些方法也存在于Channel和ChannelPipeline自己上。若是调用Channel或者ChannelPipeline上的方法,它们将沿着整个ChannelPipeline进行传播,而调用ChannelHandlerContext上的相同方法,则从当前所关联的ChannelHandler开始,而且只会传播给位于该ChannelHandler的下一个可以处理该事件的ChannelHandler。
方法名称 | 描述 |
---|---|
alloc | 返回和这个实例相关的Channel所配置的ByteBufAllocator |
bind | 绑定到给定的SocketAddress,并返回ChannelFuture |
channel | 返回绑定到这个实例的Channel |
close | 关闭Channel,并返回ChannelFuture |
connect | 链接给定的SocketAddress,并返回ChannelFuture |
deregister | 从以前分配的EventExecutor注销,并返回ChannelFuture |
disconnect | 从远程节点断开,并返回ChannelFuture |
executor | 返回调度事件的EventExecutor |
fireChannelActive | 触发对下一个ChannelInboundHandler上的channelActive()方法的调用 |
fireChannelInActive | 触发下一个ChannelInboundHandler上的channelInActive()方法 |
fireChannelRead | 触发对下一个ChannelInboundHandler上的channelRead()方法 |
fireChannelReadComplete | 触发对下一个ChannelInboundHandler上的channelReadComplete()方法的调用 |
fireChannelRegistered | 触发对下一个ChanneInboundHandler上的fireChannelRegistered方法的调用 |
fireChannelUnregistered | 触发对下一个ChannelInboundHandler上的fireChannelUnregistered方法的调用 |
fireChannelWritabilityChanged | 触发对下一个ChannelInboundHandler上的fireChannelWritabilityChanged方法的调用 |
fireExceptionCaught | 触发对下一个ChannelInboundHandler上的fireExceptionCaught方法的调用 |
fireUserEventTriggered | 触发对下一个ChannelInboundHandler上的fireUserEventTriggered(Object evt)方法的调用 |
handler | 返回绑定到这个实例的ChannelHandler |
isRemoved | 若是从关联的ChannelHandler已经被从ChannelPipeline中移除则返回true |
name | 返回这个实例的惟一名称 |
pipeline | 返回这个实例相关联的ChannelPipeline |
read | 将数据从Channel读取到第一个入站缓冲区;若是读取成功则触发一个channelRead事件,并(在最后一个消息被被读取完成后)通知ChannelInboundHandler的channelReadComplete(ChannelHandlerContext)方法 |
write | 经过这个实例写入消息并通过ChannelPipeline |
writeAndFlush | 经过这个实例写入并冲刷消息并通过ChannelPipeline |
让ChannePipeline从某个特定的点开始传播的缘由:
要想调用从某个特定的ChannelHandler开始处理的过程,必须获取到在(ChannelPipeline)该ChannelHandler以前的hannelHandler所关联的ChannelHandlerContext。这个ChannelHandlerContext将调用和它所关联的ChannelHandler以后的ChannelHandler。
一个ChannelHandler能够从属于多个ChannelPipeline,因此它(同一个ChannelHandler)也能够绑定到多个ChannelHandlerContext实例。用于这种用法的ChannelHandler必须使用@Shareable注解标注;不然将它添加到多个ChannelPipeline时将会触发异常。显而易见,为了安全地被用于多个并发的Channel(即链接),这样的ChannelHandler必须是线程安全的。
为什么要共享一个ChannelHandler?
在多个ChannelPipeline中安装同一个ChannelHandler的一个常见缘由是用于收集跨越多个Channel的统计信息。
若是在处理入站事件的过程当中有异常被抛出,那么它将从它在ChannelInboundHandler里被触发的那一点开始流经ChannelPipeline。若是想要处理这种类型的入站异常,必须在你的ChannelInboundHandler中重写exceptionCaught(ChannelHandlerContext,Throwable)
异常会按照入站方向流动,因此通常处理异常的逻辑一般都在最后一个ChannelInboundHandler中实现
用于处理出站操做中的正常完成以及异常的选项,都基于如下的通知机制: