文章目录
ChannelHandler
-
ChannelHandler是Netty中的通道事件处理器,它是我们使用Netty过程中中最常用的组件,也是我们开发过程集中的组件。ChannelHandler可以处理各种事件,比如:连接建立、连接断开、数据接收、异常等。ChannelHandler会处理IO事件,并且将事件转发给它所在ChannelPipeline中的下一个ChannelHandler;
-
源代码对应的是transport模块
一、类和继承关系
- 从图中可以看到Channel和其主要的子类的继承关系:
- ChannelHandler:顶层接口
- ChannelInboundHandler体系(黄颜色部分):入站事件处理器接口
- ChannelOutboundHandler(绿颜色部分):出站事件处理器接口
- ChannelDuplexHandler(红颜色部分):出站入站事件处理器
- 另外还有带有Adapter后缀的实现类,都是一些接口的骨架实现
- 最下面基本都是对应部分功能的抽象类:
MessageToByteEncoder:编码消息( Message -> ByteBuf )
ByteToMessageDecoder:解码消息( ByteBuf -> Message )
二、ChannelHandler
- ChannelHandler是一个顶层接口:
public interface ChannelHandler {
/**
* Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events.
*
* ChannelHandler被添加到ChannelPipeline中以进行处理事件时,该方法会被调用。
*
* 该方法,一般用于 ChannelHandler 的初始化的逻辑
*/
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events
* anymore.
* ChannelHandler被移除ChannelPipeline时,该方法会被调用。
*
* 该方法,一般用于 ChannelHandler 的销毁的逻辑
*/
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called if a {@link Throwable} was thrown.
*
* 获取到异常时被调用。目前被废弃,移到 ChannelInboundHandler 接口中,作为对 Exception Inbound 事件的处理
*
* @deprecated is part of {@link ChannelInboundHandler}
*/
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
/**
* 注解表示同一个ChannelHandler实例可以添加到多个ChannelPipeline,可以在ChannelPipeline之间安全共享
* 反之如果没有该注解,那么添加到不同的ChannelPipeline需要new出不同的实例,ChannelPipeline之间不能共享
*/
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
}
- ChannelHandler接口定义的方法不多,主要是添加和移除ChannelPipeline时回调的方法,以及是否支持在ChannelPipeline之间共享的注解;
三、两种类型处理器
3.1 ChannelInboundHandler
- ChannelInboundHandler接口代表入站处理器,定义了入站处理器的方法,部分方法如下:
/**
* {@link ChannelHandler} which adds callbacks for state changes. This allows the user to hook in to state changes easily.
* 入站处理器接口,定义了一系列回调方法,在状态改变的时候回调对应方法
*/
public interface ChannelInboundHandler extends ChannelHandler {
/**
* Channel注册到EventLoop的时候,调用
*/
void channelRegistered(ChannelHandlerContext ctx) throws Exception;
/**
* Channel从EventLoop注销的时候,调用
*/
void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
/**
* Channel活跃的时候,调用
*/
void channelActive(ChannelHandlerContext ctx) throws Exception;
/**
* Channel不活跃的时候,调用,此时生命周期马上结束
*/
void channelInactive(ChannelHandlerContext ctx) throws Exception;
/**
* Channel读取到消息的时候调用
*/
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
/**
* 抛出异常时调用
*/
@Override
@SuppressWarnings("deprecation")
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
3.2 ChannelOutboundHandler
- ChannelInboundHandler接口代表出站处理器,定义了出站处理器的方法,部分方法如下:
/**
* 发生IO出站事件的时候,方法会得到通知调用
*/
public interface ChannelOutboundHandler extends ChannelHandler {
/**
* Called once a bind operation is made.
* 绑定操作被执行的时候调用
*/
void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;
/**
* Called once a connect operation is made.
* 连接操作执行的时候调用
*/
void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
SocketAddress localAddress, ChannelPromise promise) throws Exception;
/**
* Called once a disconnect operation is made.
* 断开连接的时候调用
*/
void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
/**
* Called once a close operation is made.
* 关闭的时候调用
*/
void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
/**
* Called once a deregister operation is made from the current registered {@link EventLoop}.
* 注销的时候调用
*/
void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
/**
* Intercepts {@link ChannelHandlerContext#read()}.
* 拦截ChannelHandlerContext#read()方法
*/
void read(ChannelHandlerContext ctx) throws Exception;
/**
* Called once a write operation is made. The write operation will write the messages through the
* {@link ChannelPipeline}. Those are then ready to be flushed to the actual {@link Channel} once
* {@link Channel#flush()} is called
* 写操作时候调用,写的消息会经过ChannelPipeline,调用Channel#flush()的时候,消息会被flush到Channel
*/
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;
/**
* Called once a flush operation is made. The flush operation will try to flush out all previous written messages that are pending.
* flush会将前面前部pending的消息flush到Channel
*/
void flush(ChannelHandlerContext ctx) throws Exception;
}
四、适配器类
- 前面介绍的两重接口的继承导致了子类实现的时候需要重写大量的方法,但是我们编写代码的时候可能只会关系其中的某一两个方法,为了简化出现了适配器类。
- ChannelHandlerAdapter、ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter这几个类的出现有一个很重要的目的是简化子类,多数的ChannelHandler会选择性地拦截和处理某个或者某些事件而忽略其他事件,忽略的事件由其他的ChannelHandler 进行拦截和处理。如果直接继承顶层接口会导致之类需要实现很多自己不关心的接口,在Adapter中所有接口实现都是事件透传,具体的子类只需要继承Adapter然后实现自己关心的接口方法即可。
4.1 ChannelHandlerAdapter
- ChannelHandlerAdapter的后面二者的抽象父类,它实现了ChannelHandler接口,做了很简单的实现,大部分都是空实现
/**
* Skeleton implementation of a {@link ChannelHandler}.
* ChannelHandler的骨架实现
*/
public abstract class ChannelHandlerAdapter implements ChannelHandler {
/**
* 是否已经初始化,仅用于完整性检查,所以不需要volatile;Not using volatile because it's used only for a sanity check.
*/
boolean added;
/**
* 如果isSharable()返回true,会抛出IllegalStateException异常,isSharable()就是判断是否有@Sharable注解
*/
protected void ensureNotSharable() {
if (isSharable()) {
throw new IllegalStateException("ChannelHandler " + getClass().getName() + " is not allowed to be shared");
}
}
public boolean isSharable() {
Class<?> clazz = getClass();
Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
Boolean sharable = cache.get(clazz);
if (sharable == null) {
sharable = clazz.isAnnotationPresent(Sharable.class);
cache.put(clazz, sharable);
}
return sharable;
}
/**
* 默认不做任何事情
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// NOOP
}
/**
* 默认不做任何事情
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// NOOP
}
/**
* 调用ChannelPipeline中的下一个ChannelHandler
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.fireExceptionCaught(cause);
}
}
4.2 ChannelInboundHandlerAdapter
- 处理入站事件,继承ChannelHandlerAdapter抽象类并实现ChannelInboundHandler,每个实现方法默认无任何逻辑,直接转发到下一个节点,子类如果有自定义的逻辑可重写对应的方法,如果是定义一个入站处理器就可以继承它。
- 下面列出的全部方法,默认都是转发到下一个节点,子类都可以重写这些方法;
/**
* 处理入站事件,继承ChannelHandlerAdapter抽象类并实现ChannelInboundHandler的全部方法,每个实现方法默认无任何
* 逻辑,直接转发到下一个节点,子类如果有自定义的逻辑可重写对应的方法。
*/
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelRegistered();
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelUnregistered();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelReadComplete();
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
ctx.fireUserEventTriggered(evt);
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelWritabilityChanged();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.fireExceptionCaught(cause);
}
}
4.3 ChannelOutboundHandlerAdapter
- 处理出站事件,继承ChannelHandlerAdapter抽象类并实现ChannelOutboundHandler接口,每个实现方法默认无任何逻辑,直接转发到下一个节点,子类如果有自定义的逻辑可重写对应的方法,如果是定义一个出站处理器就可以继承它。
- 和ChannelInboundHandlerAdapter一样,下面列出的全部方法,默认都是转发到下一个节点,子类都可以重写这些方法;
/**
* ChannelOutboundHandler的骨架实现,默认无任何逻辑,直接转发到下一个节点,子类如果有自定义的逻辑可重写对应的方法。
*/
public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
ctx.bind(localAddress, promise);
}
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.disconnect(promise);
}
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.close(promise);
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.deregister(promise);
}
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
ctx.read();
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ctx.write(msg, promise);
}
@Override
public void flush(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}
4.4 ChannelDuplexHandler
- ChannelDuplexHandler继承了ChannelInboundHandlerAdapter,相当于实现了ChannelInboundHandler,同时还实现了ChannelOutboundHandler接口,因此支持Inbound(入站)和Outbound(出站)事件的处理;
- ChannelDuplexHandler代码和ChannelOutboundHandlerAdapter有很多类似的,但是因为不支持多继承只能自己再实现一次,看继承图发现二者是没有继承关系的,它对ChannelOutboundHandler的实现和ChannelOutboundHandlerAdapter几乎是一模一样的。完全可以理解为ChannelDuplexHandler具备 ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter的特性,在定义一个双向处理器的时候,就可以继承ChannelDuplexHandler来实现。
/**
* {@link ChannelHandler} implementation which represents a combination out of a {@link ChannelInboundHandler} and
* the {@link ChannelOutboundHandler}.
*
* It is a good starting point if your {@link ChannelHandler} implementation needs to intercept operations and also
* state updates.
* ChannelDuplexHandler继承了ChannelInboundHandlerAdapter,相当于实现了ChannelInboundHandler,同时还实现了ChannelOutboundHandler接
* 口,因此支持Inbound(入站)和Outbound(出站)事件的处理:
*/
public class ChannelDuplexHandler extends ChannelInboundHandlerAdapter implements ChannelOutboundHandler {
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
ctx.bind(localAddress, promise);
}
/**
* Calls {@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
ctx.connect(remoteAddress, localAddress, promise);
}
/**
* Calls {@link ChannelHandlerContext#disconnect(ChannelPromise)} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.disconnect(promise);
}
/**
* Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.close(promise);
}
/**
* Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.deregister(promise);
}
/**
* Calls {@link ChannelHandlerContext#read()} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
ctx.read();
}
/**
* Calls {@link ChannelHandlerContext#write(Object, ChannelPromise)} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ctx.write(msg, promise);
}
/**
* Calls {@link ChannelHandlerContext#flush()} to forward
* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void flush(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}
五、小结
- 本文比较简单,类的继承关系也比较清晰,主要是了解ChannelHandler的继承体系,尚未涉及到对应具体功能的ChannelHandler实例;
- Channel -> ChannelInboundHandler和ChannelOutboundHandler -> ChannelHandlerAdapter、ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter,以及ChannelDuplexHandler,结构清晰
- 后面的文章再来看具体的ChannelHandler实例;