Netty笔记1:线程模型
Netty笔记2:零拷贝
Netty笔记3:NIO编程
Netty笔记4:Epoll
Netty笔记5:Netty开发实例
Netty笔记6:Netty组件
Netty笔记7:ChannelPromise通知处理
Netty笔记8:ByteBuf使用介绍
Netty笔记9:粘包半包
Netty笔记10:LengthFieldBasedFrameDecoder
Netty笔记11:编解码器
Netty笔记12:模拟Web服务器
Netty笔记13:序列化
文章目录
Netty中的操作都是异步的,它继承于
ChannelFuture
,用于异步通知,如果我们要及时得到操作结果,该如何?
Netty在writeAndFlush
时,会默认写入一个Promise
(如果我们没有指定),位置:
io.netty.channel.AbstractChannelHandlerContext#writeAndFlush(java.lang.Object)
API如下:
public interface ChannelPromise extends ChannelFuture, Promise<Void> {
// 返回管理的channel
@Override
Channel channel();
// 这个方法可以忽略,void类型的结果是null
@Override
ChannelPromise setSuccess(Void result);
// 设置异步操作成功
ChannelPromise setSuccess();
// 尝试设置成功,在没有设置过状态时,返回true,如果已经有状态返回false
boolean trySuccess();
// 设置失败状态,并可传入参数,描述失败原因
@Override
ChannelPromise setFailure(Throwable cause);
// 下面的listener是状态变更的监听器
// 通常可以通过这个监听器添加业务处理
@Override
ChannelPromise addListener(GenericFutureListener<? extends Future<? super Void>> listener);
@Override
ChannelPromise addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
// 移除监听器
@Override
ChannelPromise removeListener(GenericFutureListener<? extends Future<? super Void>> listener);
@Override
ChannelPromise removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
// 用于阻塞当前线程,和 ChannelFuture 的一样
@Override
ChannelPromise sync() throws InterruptedException;
// 中断当前线程,注意它并没抛出异常,需要Thread判断
@Override
ChannelPromise syncUninterruptibly();
// 等待,直到IO操作完成
@Override
ChannelPromise await() throws InterruptedException;
@Override
ChannelPromise awaitUninterruptibly();
/**
* 返回一个新下ChannelPromise,判断isVoid,不理解
*/
ChannelPromise unvoid();
}
不妨定义一个Handler
测试一下:
public class ClientOutHandler extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
// 运行时异常
int i = 1/0;
super.write(ctx, msg, promise);
}
}
它的上一层是:io.netty.channel.AbstractChannelHandlerContext#invokeWrite0
private void invokeWrite0(Object msg, ChannelPromise promise) {
try {
((ChannelOutboundHandler) handler()).write(this, msg, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}
它最终会进入到notifyOutboundHandlerException
,然后把异常设置到promise
中:
public static void tryFailure(Promise<?> p, Throwable cause, InternalLogger logger) {
// 异常信息写入到Promise成功后,直接返回,不然就把信息打印出来
if (!p.tryFailure(cause) && logger != null) {
Throwable err = p.cause();
if (err == null) {
logger.warn("Failed to mark a promise as failure because it has succeeded already: {}", p, cause);
} else if (logger.isWarnEnabled()) {
logger.warn(
"Failed to mark a promise as failure because it has failed already: {}, unnotified cause: {}",
p, ThrowableUtil.stackTraceToString(err), cause);
}
}
}
所以,我们需要稍微改一下:
// write时,直接newPromise()创建的promise,最后返回的,所以需要使用返回值才能正确添加监听器
ChannelFuture cf = future.channel().writeAndFlush(info);
// 这里使用write时返回promise对象
cf.addListener((ChannelFuture f)->{
if (!f.isSuccess()) {
System.out.println("写入失败!");
f.cause().printStackTrace();
}
});
上面我只是示例了一个异常的处理,它的作用是通知,可以在异步操作成功或失败时执行业务。
通过ChannelPromise
的API可以知道,他可以实现成功、完成、可取消、已取消
状态通知,也可以完成设置和其他一些功能。
注意(总结)
我们执行异步操作时,需要对这个操作的结果或状态做出某些处理时,就需要对这个异步操作的Future
增加监听器,然后参数是ChannelPromise
,这个就是异步操作的通知对象。**