Netty是一个用于快速开发可维护的高性能协议服务器和客户端的异步的事件驱动网络应用框架.
其他资料:
Java IO 介绍
1 . 相关概念
1) 事件: 事件代表过去发生的事件,事件既是技术架构概念,也是业务概念。一个事件代表某个已经发生的事情,在计算机系统中,事件是由一个对象表达,其包含有关事件的数据,比如发生的时间,地点等等。这个事件对象可以存在在一个消息或数据库记录或其他组件的形式中,这样一个对象称为”一个事件”。事件本身是不可变的值对象.
2) EDA: 以事件为驱动的编程模型称为事件驱动架构EDA.
3) 请求驱动与事件驱动: 请求驱动+消息系统和事件驱动+消息系统有本质区别,前者是由请求者作为消息生产者,主要目的是为了得到响应,因此是一种请求响应模型;而后者重点是在消息消费者,不是在消息生产者,业务逻辑站在消费者角度完成,业务逻辑的完成靠事件驱动来执行,而前者业务逻辑是在消息生产者完成,当业务逻辑中需要什么依赖或资源,依靠发送消息来拉取完成。这两种区别本质是拉Poll和推Push的区别。
2 . Netty中的事件驱动模型中的核心组件
1) Channels : 一个Channel是Java NIO的一个基本抽象。它代表了:一个连接到比如硬件设备,文件,网络socket等实体的开放连接,或者是一个能够完成一种或多种譬如读或写等不同I/O操作的程序
2) Callbacks : 一个callback就是一个方法,一个提供给另一个的方法的引用。这让另一个方法可以在适当的时候回过头来调用这个callback方法。Callbacks在很多编程情形中被广泛使用,是用于通知相关方某个操作已经完成最常用的方法之一。
Netty在处理事件时内部使用了callback;当一个callback被触发,事件可以被ChannelHandler的接口实现处理。下面的代码清单是这样一个例子:当一个新的连接建立后,ChannelHandler的callback方法channelActive()会被调用,然后打印一条消息。
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("一个新的连接建立了");
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("开始从通道读取数据");
ctx.write(msg);
}
}
3) Futures Events : 一个Future提供了另一个当操作完成时如何通知应用的方法。Future对象充当了一个存放异步操作结果的占位符(placeholder)角色;它会在将来某个时间完成并且提供对操作结果的访问。
JDK搭载了接口java.util.concurrent.Future, 但是提供的接口实现只允许你手动检查操作是否已经完成,或者就一直阻塞到操作完成。这非常麻烦,所以Netty提供了它自己的ChannelFuture实现,用于执行异步操作。
ChannelFuture提供了额外的方法让我们可以注册一个或者多个ChannelFutureListener实例。监听者的callback方法operationComplete()在操作完成时被调用。然后监听者可以查看这个操作是否成功完成,还是出错了。如果出错了,我们可以从future获取Throwable。简单来说,ChannelFutureListener提供的通知机制免去了手动检查操作完成情况的麻烦。
每个Netty输出的I/O操作都会返回一个ChannelFuture;就是说,没有一个操作是阻塞的。就像我们之前所说的,Netty由下至上都是异步和事件驱动的。
代码清单1.3中,一个ChannelFuture做为一个I/O操作的一部分被返回。这里,connect()会无阻塞地直接返回,调用会在后台完成。什么时候会完成取决于多个因素,但是这个担心已经从代码里被抽离(abstract away)出来了。因为这个线程没有阻塞在等待这个操作完成,它可以同时做其他事情,因此更有效率地利用资源。
Channel channel = new NioServerSocketChannel();
io.netty.channel.ChannelFuture future = channel.connect(new InetSocketAddress("127.0.0.1", 80));//异步连接远端
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(io.netty.channel.ChannelFuture future) throws Exception {
if (future.isSuccess()){//操作成功,进行消息会传
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello kitty!".toCharArray(), Charset.defaultCharset());
future.channel().writeAndFlush(byteBuf);
}else {//操作失败,打印错误信息
Throwable cause = future.cause();
cause.printStackTrace();
}
}
});
4) Events和handlers : Netty用细分的events来通知我们状态的变化或者操作的状况。这让我们可以基于发生的events来触发适当的行为。这类行为可能包括
- 日志记录 数据传送 流控制 应用逻辑
Netty是一个网络编程框架,所以events按它们和输入或者输出数据流的关系来分类。可能被输入数据或者相关状态改变触发的events包括:
- 活跃或者停用的连接 读数据 用户events 错误events
而输出event则是会触发将来行为的操作的结果,可能会是:
- 打开或者关闭到远端的连接 写或者刷数据到一个socket
每一个event都可以被分派到一个用户实现的handler对象的方法。这是一个事件驱动的模型如何直接转变为应用模块的好例子。图1.3展示了一个event如何被一串这样的event handler处理。
3 . 总结
Netty的异步编程模型是建立在Futures和callbacks概念之上的,在更深一层分派事件到handler方法。这些元素结合起来提供了一个处理环境,让你的应用逻辑可以逐步发展而不用关心网络操作。
EventLoop自己仅由一个线程驱动,这个线程处理一个Channel所有的I/O事件,这个关系在Eventloop的生命周期内不会改变。