Netty核心组件
- Channel
- 回调
- Future
- 事件和ChannelHandler
Channel
Channel是Java NIO的一个基本构造。
它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作。
可以把Channel看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者关闭,连接或者断开连接。
回调
一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得接受回调的方法可以在适当的时候调用被回调的方法。
Netty在内部使用了回调来处理事件,当一个回调被触发时,相关的事件可以被一个Interface——ChannelHandler的实现处理。
代码示例:
public class ConnectHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client " + ctx.channel().remoteAddress() + " connected");
}
}
Funture
Future提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
JDK预置了interface java.util.concurrent.Future,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以Netty提供了它自己的实现——ChannelFuture,用于在执行异步操作的时候使用。
ChnnelFuture提供了几种额外的方法,这些方法使得我们能够注册一个或者多个ChannelFutureListener实例。监听器的回调方法operationComplete(),将会在对应的操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者,我们可以检索产生的Throwable。简而言之,由ChannelFutureListener提供的通知机制消除了手动检查对应的操作是否完成的必要。
每个Netty的出站I/O操作都将返回一个ChannelFuture;也就是说,他们都不会阻塞。
以下代码示例展示了一个ChannelFuture作为一个I/O操作的一部分返回的例子以及如何利用ChannelFutureListener。这里connect()方法将会直接返回,而不会阻塞,该调用将会在后台完成。
Channel channel = ...;
ChannelFuture future = channel.connect(
new InetSocketAddress("192.168.0.1", 25)
);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if(future.isSuccess()) {
ByteBuf buffer = Unpooled.copiedBuffer("Hello", Charset.defaultCharset());
ChannelFuture wf = future.channel().writeAndFlush(buffer);
....
} else {
Throwable cause = future.cause();
cause.printStackTrace();
}
}
})
可以把ChannelFutureListener看作是回调的一个更加精细的版本。事实上,回调和Future是相互补充的机制。
事件和ChannelHandler
Netty使用不同的事件来通知我们状态的改变或者是操作的改变。这使得我们能够基于已经发生的事件来触发适当的动作。这些动作可能是:
- 记录日志
- 数据转换
- 流控制
- 应用程序逻辑
Netty是一个网络编程框架,所以事件是按照它们与入站或出站数据流的相关性进行分类的。
与入站相关的事件 | 与出站相关的事件 |
---|---|
连接已被激活或者连接失活 | 打开或者关闭到远程节点的连接 |
数据读取 | 将数据写到或者冲刷到套接字 |
用户事件 | |
错误事件 |
每个事件都可以被分发给ChannelHandler类中的某个用户实现的方法。