’
netty线程模型
为了让NIO更好的利用多线程特性,Netty实现了Reactor线程模型。Reactor模型中有四个核心概念:
- Resources资源(请求/任务)
- Synchronous Event Demultiplexer 同步事件复用器
- Dispatcher 分配器
- Request Handler 请求处理器
EventLoopGroup
初始化过程
/*未完...*/
线程组本质上是循环创建多个NioEventLoop,通过executor创建.
@Override
protected EventLoop newChild(Executor executor,Object... args) throws Exception{
return new NioEventLoop(this, executor,(SelectorProvider) args[0],((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
EventLoop 将通道注册到EventLoop的selector上,进行事件轮询.在有线程在调用NioEventLoop的时候,判断executor方法的调用者是不是在EventLoop同一个线程,如果不是一个线程,则调用启动方法.
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
} else {
boolean inEventLoop = this.inEventLoop();
if (inEventLoop) {
this.addTask(task);
} else {
this.startThread();
this.addTask(task);
if (this.isShutdown() && this.removeTask(task)) {
reject();
}
}
if (!this.addTaskWakesUp) {
this.wakeup(inEventLoop);
}
}
}
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {//创建线程开始执行run方法,每个EventLoop都是执行run
/*
run执行两件事:Selector,select的事件 和 taskQueue里面的内容
*/
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
if (state < ST_SHUTTING_DOWN) {
state = ST_SHUTTING_DOWN;
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called " +
"before run() implementation terminates.");
}
启动
EventLoop自身实现了Executor接口,当调用executor方法提交任务时,则判断是否启动,未启动则调用内置的executor创建新县城来触发run方法执行.
Bind绑定端口过程
初始化Channel:
Channel channel = channelFactory.newChannel();
init(channel);
注册:
Channel
概念
netty中的Channel是一个抽象的概念,可以理解为对JDK NIO Channel的增强和扩展.增加了很多属性和方法.
AbstractChannel |
---|
-pipeline DefaultChannelPipeline //通道内时间处理链路 |
-eventLoop //绑定的EventLoop,用于执行操作 |
-unsafe Unsafe //提供I/O相关的操作的封装 |
# config() ChannelConfig //返回通道配置信息 |
+read() Channel //开始读数据,触发读取链路调用 |
+wirte(Object msg) ChannelFuture //写数据,触发链路调用 |
+bind(SocketAddress socketAddress) ChannelFuture //绑定 |
责任链模式
责任链模式为请求创建了一个处理对象的链.
发起请求和具体处理请求的过程进行解耦: 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递.
Netty中事件的定义
inbound入站事件
事件 | 描述 |
---|---|
fireChannelRegistered | channel注册事件 |
fireChannelUnregistered | channel解除注册事件 |
fireChannelActive | channel活跃事件 |
fireChannelInactive | channel非活跃事件 |
fireExceptionCaught | 异常事件 |
fireUserEventTriggered | 用户自定义事件 |
fireChannelRead | channel读事件 |
fireChannelReadComplete | channel读完成事件 |
fireChannelWritabilityChanged | channel写状态变化事件 |
outbound出站事件
事件 | 描述 |
---|---|
bind | 端口绑定事件 |
connect | 连接事件 |
disconnect | 断开连接事件 |
close | 关闭事件 |
deregister | 解除注册事件 |
flush | 刷新数据到网络事件 |
read | 读事件,用于注册OP_READ到selector |
write | 写事件 |
writeAndFlush | 写出数据事件 |
Pipeline中的handler是什么
ChannelHandler
用于处理I/O事件或拦截I/O操作,并转发到ChannelPipeline中的下一个处理器.这个顶级接口定义功能很弱,实际使用时会去实现下面两大子接口:
- 处理入站I/O事件的ChannelInboundHandler
- 处理出站I/O操作的ChannelOutboundHandler
适配器类
为了开发方便,避免所有的handler去实现一遍接口方法,Netty提供了简单的实现类:
ChanelInboundHandlerAdapter 处理入站I/O事件
ChannelOutboundHandlerAdapter 处理出站I/O操作
ChannelDuplexHandler 来支持同事处理入站和出站事件
ChannelHandlerContext
实际存储在Pipeline中的对象并非ChannelHandler,而是上线文对象,将Handler包裹在上下文对象中,通过上下文对象与它所属的ChannelPipeline交互,向上或向下传递事件或者修改pipeline都是通过上下文对象.
维护Pipeline中的handler
ChannelPipeline是线程安全的,ChannelHandler可以在任何时候添加或删除.
方法名称 | 描述 |
---|---|
addFirst | 最前面插入 |
addLast | 最后面插入 |
addBefore | 插入到指定处理器前面 |
addAfter | 插入到指定处理器后面 |
remove | 移除指定处理器 |
removeFirst | … |
removeLast | … |
replace | 替换指定处理器 |
Netty零拷贝机制
ByteBuf
JDK ByteBuffer 的缺点:
- 无法动态扩容
- API使用复杂
Netty的ByteBuf的优点:
- API操作便捷性
- 动态扩容
- 多种ByteBuf实现
- 高效的零拷贝机制
三个重要属性:
- capacity
- readerIndex 读取位置
- writerIndex 写入位置