本文转载自渡一教育
一.ByteBuf
NIO中ByteBuffer的缺点:
1)长度固定,无法动态的扩容和缩容,缺乏灵活性
2) 使用一个position记录读写的索引位置,在读写模式切换时需手动调用flip方法,增加了使用的复杂度。
3)功能有限,使用过程中往往需要自行封装
1.分类
按照内存的位置,分为堆内存缓冲区 heap buffer、直接内存缓冲区direct buffer、复合内存缓冲区composite buffer
1)heap buffer(堆内存缓冲区)
将数据存储到JVM的堆空间中,实际使用字节数组byte[]来存放
优点:数据可以快速的创建和释放,并且能够直接访问内部数组
缺点:在读写数据时,需要将数据复制到直接缓冲区 再进行网络传输
2)direct buffer(直接内存缓冲区)
不在堆中,而是使用了操作系统的本地内存
优点:在使用Socket进行数据传输过程中,减少一次拷贝,性能更高
缺点:释放和分配的空间更昂贵,使用时需要更谨慎
3)composite buffer(复合内存缓冲区)
将两个或多个不同内存的缓冲区合并
优点:可以统一进行操作
应用场景:在通信线程使用缓冲区时,往往使用direct buffer,而业务消息使用缓冲区时,往往使用heap buffer,在解决http包,请求头+请求体特性不同而选择不同位置存储时,可以将两者拼接使用
public class TypeTest {
public static void main(String[] args) {
ByteBuf buf = Unpooled.copiedBuffer("hello bytebuf", CharsetUtil.UTF_8);
if (buf.hasArray()) {
System.out.println("堆内存缓冲区");
System.out.println(new String(buf.array()));
}
ByteBuf buf1 = Unpooled.buffer();
ByteBuf buf2 = Unpooled.directBuffer();
CompositeByteBuf buf3 = Unpooled.compositeBuffer();
buf3.addComponents(buf1, buf2);
Iterator<ByteBuf> iterator = buf3.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
4)池化
对于内存空间分配和释放的复杂度和效率,netty通过内存池的方式来解决
内存池,可以循环利用ByteBuf,提高使用率。但是管理和维护较复杂
Unpooled正是非池化缓冲区的工具类
主要区别在于,池化的内存由netty管理,非池化的内存由GC回收
5)回收方式
回收方式为引用计数,具体规则为,通过记录被引用的次数,判断当前对象是否还会被使用
当对象被调用时,引用计为+1,当对象被释放时,引用计为-1,当引用次数为0时,对象可以回收
弊端:可能引发内存泄漏
当对象不可达,JVM会通过GC回收掉,但此时引用计数可能不为0,对象无法归还内存池,会导致内存泄漏。netty只能通过对内存缓冲区进行采样检查
public class RefCntTest {
public static void main(String[] args) {
ByteBuf buf = Unpooled.buffer(10);
System.out.println(buf);
System.out.println(buf.refCnt());
buf.retain();
System.out.println(buf.refCnt());
buf.release();
System.out.println(buf.refCnt());
buf.release();
System.out.println(buf);
}
}
2.工作原理
和ByteBuffer不同在于,增加了一个指针,通过两个指针记录读模式和写模式时的索引位置,读指针叫做readerIndex,写指针叫做writerIndex
1) 读写分离
当执行clear()方法时,索引位置清空回初始位置,但数据保持不变
mark和reset方法在ByteBuf中同样适用,如markReaderIndex和resetReaderIndex
public class IndexTest {
public static void main(String[] args) {
ByteBuf buf = Unpooled.buffer();
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("--------写入hello index");
buf.writeBytes("hello index".getBytes());
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("readableBytes: " + buf.readableBytes());
System.out.println("--------读取hello");
for (int i = 0; i < 5; i++) {
System.out.print((char) buf.readByte());
}
System.out.println();
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("readableBytes: " + buf.readableBytes());
System.out.println("--------读取index 并回退");
buf.markReaderIndex();
int end = buf.writerIndex();
for (int i = buf.readerIndex(); i < end; i++) {
System.out.print((char) buf.readByte());
}
System.out.println();
buf.resetReaderIndex();
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("readableBytes: " + buf.readableBytes());
buf.discardReadBytes();
System.out.println("--------回收可废弃空间");
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("readableBytes: " + buf.readableBytes());
buf.clear();
System.out.println("--------调用clear方法");
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
System.out.println("writableBytes: " + buf.writableBytes());
System.out.println("readableBytes: " + buf.readableBytes());
}
}
2)深浅拷贝
浅拷贝,拷贝的是对对象的引用,并没有创建新对象,新对象和原对象之间互相影响
深拷贝,拷贝的是整个对象,和原对象之间完全独立
duplicate和slice方法,达成全部浅拷贝和部分浅拷贝
copy,部分深拷贝,部分代表的是可读空间
public class CopyTest {
public static void main(String[] args) {
ByteBuf buf = Unpooled.buffer();
buf.writeBytes("hello bytebuf copy".getBytes());
System.out.println("----------初始化bytebuf");
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
ByteBuf newBuf = buf.duplicate();
System.out.println("----------duplicate newBuf");
System.out.println("newBuf capacity: " + newBuf.capacity());
System.out.println("newBuf readerIndex: " + newBuf.readerIndex());
System.out.println("newBuf writerIndex: " + newBuf.writerIndex());
newBuf.writeBytes(" from newBuf".getBytes());
System.out.println("----------duplicate add data");
System.out.println("newBuf writerIndex: " + newBuf.writerIndex());
buf.writerIndex(30);
for (int i = 0; i < 13; i++) {
System.out.print((char) buf.readByte());
}
System.out.println();
System.out.println("capacity: " + buf.capacity());
System.out.println("readerIndex: " + buf.readerIndex());
System.out.println("writerIndex: " + buf.writerIndex());
ByteBuf sliceBuf = buf.slice();
System.out.println("-----------sliceBuf");
System.out.println("capacity: " + sliceBuf.capacity());
System.out.println("readerIndex: " + sliceBuf.readerIndex());
System.out.println("writerIndex: " + sliceBuf.writerIndex());
ByteBuf copyBuf = buf.copy();
System.out.println("-----------copyBuf");
System.out.println("capacity: " + copyBuf.capacity());
System.out.println("readerIndex: " + copyBuf.readerIndex());
System.out.println("writerIndex: " + copyBuf.writerIndex());
copyBuf.writeBytes(" from copyBuf".getBytes());
copyBuf.writerIndex(43);
for (int i = copyBuf.readerIndex(); i < 43; i++) {
System.out.print((char) copyBuf.readByte());
}
System.out.println();
System.out.println("-----------原buf");
buf.writerIndex(43);
for (int i = buf.readerIndex(); i < 43; i++) {
System.out.print((char) buf.readByte());
}
}
}
3.扩容机制
1)ByteBuffer的存储
ByteBuffer在put数据时,会校验剩余空间是否不足,如果不足,会抛出异常
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put("pz".getBytes());
-----------------------------------------------------------
public final ByteBuffer put(byte[] src) {
return put(src, 0, src.length);
}
public ByteBuffer put(byte[] src, int offset, int length) {
checkBounds(offset, length, src.length);
if (length > remaining())
throw new BufferOverflowException();
int end = offset + length;
for (int i = offset; i < end; i++)
this.put(src[i]);
return this;
}
手动对ByteBuffer扩容,可以在put之前,先校验剩余空间是否足够
如果不足够,创建一个新的ByteBuffer,新的容量确保足够,旧的buffer数据拷贝到新的buffer中,然后继续存储数据
2) ByteBuffer的存储和扩容
当写数据时,先判断是否需要扩容,如果当前空间较小(<4M),以64作为基数倍增(10 -> 64 -> 128 -> 256), 如果当前空间较大(>4M), 每次扩容都增加4M,这种方式叫做"步进式"
public class CapacityTest {
public static void main(String[] args) {
ByteBuf buf = Unpooled.buffer(10);
System.out.println("capacity: " + buf.capacity());
for (int i = 0; i < 11; i++) {
buf.writeByte(i);
}
System.out.println("capacity: " + buf.capacity());
for (int i = 0; i < 65; i++) {
buf.writeByte(i);
}
System.out.println("capacity: " + buf.capacity());
}
}
public abstract ByteBuf writeByte(int value);
@Override
public ByteBuf writeByte(int value) {
ensureWritable0(1);
_setByte(writerIndex++, value);
return this;
}
final void ensureWritable0(int minWritableBytes) {
final int writerIndex = writerIndex();
final int targetCapacity = writerIndex + minWritableBytes;
if (targetCapacity <= capacity()) {
ensureAccessible();
return;
}
if (checkBounds && targetCapacity > maxCapacity) {
ensureAccessible();
throw new IndexOutOfBoundsException(String.format(
"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
writerIndex, minWritableBytes, maxCapacity, this));
}
final int fastWritable = maxFastWritableBytes();
int newCapacity = fastWritable >= minWritableBytes ? writerIndex + fastWritable
: alloc().calculateNewCapacity(targetCapacity, maxCapacity);
capacity(newCapacity);
}
public int maxFastWritableBytes() {
return writableBytes();
}
@Override
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
checkPositiveOrZero(minNewCapacity, "minNewCapacity");
if (minNewCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
minNewCapacity, maxCapacity));
}
final int threshold = CALCULATE_THRESHOLD;
if (minNewCapacity == threshold) {
return threshold;
}
if (minNewCapacity > threshold) {
int newCapacity = minNewCapacity / threshold * threshold;
if (newCapacity > maxCapacity - threshold) {
newCapacity = maxCapacity;
} else {
newCapacity += threshold;
}
return newCapacity;
}
int newCapacity = 64;
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
}
return Math.min(newCapacity, maxCapacity);
}
3)优势
池化的方式提高内存使用率
提出了复合型缓冲区的整合方案
增加了索引,使读写分离,使用更便捷
解决了ByteBuffer长度固定的问题,增加了扩容机制
用引用计数的方式进行对象回收
二.channel
channel是通讯的载体,对应通讯的一端,在BIO中对应Socket,NIO中对应SocketChannel,Netty中对应NioSocketChannel,ServerSocket同理
channelhandler是通道的处理器,一个channel往往有多个handler
channelpipeline是handler的容器,装载并管理handler的顺序(本质是双向链表)
如图,channel创建时,会对应创建一个channelpipeline,pipeline首先会记录一个头部的处理器handler,当pipeline进行分发时,先分发给头部,然后依次执行,执行handler全部执行完成
同时,channel创建后,会注册进EventLoop之中,EventLoop会监听事件的发生。不同的事件调用handler不同的处理方法,让流程运转起来。
channel生命周期,对应四种状态,分别为:
1) ChannelUnregistered 已创建但还未被注册到监听器中
2) ChannelRegistered 已注册到监听器EventLoop中
3) ChannelActive 连接完成处于活跃状态,此时可以接收和发送数据
4) ChannelInactive 非活跃状态,代表连接未建立或者已断开
channelhandler生命周期,对应三种状态,分别为:
1) handlerAdded 把handler添加到pipeline之中
2) handlerRemoved 从pipeline中移除
3) exceptionCaught 在处理过程中有错误产生
创建channel源码分析
ChannelFuture future = serverBootstrap.bind(8888).sync();
serverBootstrap.channel(NioServerSocketChannel.class)
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
validate();
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
.......
}
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
}
.......
}
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
在启动对象调用bind()或connect()方法时,会创建channel
本质上通过反射,使用工厂的反射实现类创建对应的实例,此时实例对象的类型是通过channel参数来设置的
ChannelHandler
类层次关系图
入站和出站:
从服务端的角度,数据从客户端发送到服务端,称之为入站,当数据处理完成返回给客户端,称之为出站。是相对的概念
从客户端的角度,数据从服务端发送给客户端,称之为入站,当数据返回给服务端,称之为出站
不论是入站还是出站,handler从一端开始,到另一端结束,以责任链的模式依次执行
责任链模式——当请求被不同的接收者处理时,每个接收者都包含对下一个接收者的引用,一个接收者处理完成后,将依次向下传递
适配器模式——出国时要使用的电源转换器(美国/日本110V 中国220V电压),作为两个不兼容的接口之间的桥梁,将类的接口转换为需要的另外一种接口
ChannelDuplexHandler是除了入站和出站handler之外的,另一个常用子类
它同时实现了ChannelInboundHandler和ChannelOutboundHandler接口,如果需要既处理入站事件又处理出站事件,可以继承此类
serverBootstrap.handler(new LoggingHandler(LogLevel.INFO))
------------------------------------------------------------------
public class LoggingHandler extends ChannelDuplexHandler{}
------------------------------------------------------------------
public class ChannelDuplexHandler extends ChannelInboundHandlerAdapter implements ChannelOutboundHandler {}
------------------------------------------------------------------
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {}
ChannelHandlerAdapter
提供了额外的isSharable()方法,用来判断handler是否可以被共享到多个pipeline之中
默认情况不共享,如果需要共享,在继承了适配器的handler上,增加注解@Sharable
@Sharable
public class LoggingHandler extends ChannelDuplexHandler {}
ChannelInboundHandler
最重要的方法是channelRead(),在使用时,需要显式的释放ByteBuf相关的内存。使用ReferenceCountUtil是引用计数的工具类
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
ReferenceCountUtil.release(msg);
}
为了减少对资源内存的管理,使用SimpleChannelInboundHandler,使用其channelRead0()方法,可以自动释放资源,使用更便利
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
boolean release = true;
try {
if (acceptInboundMessage(msg)) {
@SuppressWarnings("unchecked")
I imsg = (I) msg;
channelRead0(ctx, imsg);
} else {
release = false;
ctx.fireChannelRead(msg);
}
} finally {
if (autoRelease && release) {
ReferenceCountUtil.release(msg);
}
}
}
ChannelPipeline
pipeline中维护入站和出站链路,两条链路的执行顺序
handler只负责处理自身的业务逻辑,对通道而言,它是无状态的
通道的信息会保存到handlerContext处理器上下文中,它是连接pipeline和handler之间的中间角色
pipeline管理的是由handlerContext包裹的handler,也就是说,当添加handler时,先将其转为handlerContext,然后添加到pipeline的双向链表中
结点叫做HeadContext,尾节点叫做TailContext
ch.pipeline().addLast(new NettyServerHandler());
----------------------------------------------------------------
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
ObjectUtil.checkNotNull(handlers, "handlers");
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private static void checkMultiplicity(ChannelHandler handler) {
if (handler instanceof ChannelHandlerAdapter) {
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
h.added = true;
}
}
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
final AbstractChannelHandlerContext tail;
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
使用pipeline模式的优点:
1) 解耦,让处理器逻辑独立,可以被多个channel共享
2) channel相关信息,交给context维护
3) 具有极大的灵活性,使用处理器可以方便的添加或删除,或者更改它们的顺序
三.EventLoop
EventLoop事件循环,监听IO事件,内部封装了线程
EventLoopGroup事件循环组,是对EventLoop的管理,封装了线程池
当新建channel时,group会为其分配一个EventLoop,封装了nio中的Selector,监听通道中的所有事件
一个通道的生命周期内,所有操作都由相同的EventLoop所封装的线程处理
同时,多个通道可以由一个EventLoop处理,是多对一的关系
EventLoopGroup
类层级结构
(通过选中NioEventLoopGroup源码 - 右键 - 选中Diagrams - 选中show diagram 展示出来)
初始化流程
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
-------------------------------------------------------------------------
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
-------------------------------------------------------------------------
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}
-------------------------------------------------------------------------
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
-------------------------------------------------------------------------
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
EventLoopTaskQueueFactory queueFactory = args.length == 4 ? (EventLoopTaskQueueFactory) args[3] : null;
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
}
EventLoop
重要属性为 Selector 及其父类的父类中的 Thread
Selector用于在channel创建之后,注册其中监听后续的I/O事件
Thread用于进行轮询,在channel注册之后启动线程
注册channel
ChannelFuture future = serverBootstrap.bind(8888).sync();
--------------------------------------------------------------------------
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
validate();
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
.....
}
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
if (channel != null) {
channel.unsafe().closeForcibly();
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
注册的源码调用链路
ChannelFuture regFuture = config().group().register(channel);
------------------------------------------------------------------------------
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
------------------------------------------------------------------------------
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
------------------------------------------------------------------------------
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
----------------------------------------------------------------------------
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
eventLoop().selectNow();
selected = true;
} else {
throw e;
}
}
}
}
轮询事件的状态
AbstractChannel中register()方法,对eventLoop.execute()的调用,就是启动线程进行轮询的入口
-----------------------------------------------------------------------------
public void execute(Runnable task) {
ObjectUtil.checkNotNull(task, "task");
execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
}
private final Queue<Runnable> taskQueue;
private void execute(Runnable task, boolean immediate) {
boolean inEventLoop = inEventLoop();
addTask(task);
if (!inEventLoop) {
startThread();
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && immediate) {
wakeup(inEventLoop);
}
}
private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false;
try {
doStartThread();
success = true;
} finally {
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run();
success = true;
}
......
}
}
}
-----------------------------------------------------------------------------
protected void run() {
int selectCnt = 0;
for (;;) {
try {
int strategy;
try {
strategy = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());
switch (strategy) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
case SelectStrategy.SELECT:
long curDeadlineNanos = nextScheduledTaskDeadlineNanos();
if (curDeadlineNanos == -1L) {
curDeadlineNanos = NONE;
}
nextWakeupNanos.set(curDeadlineNanos);
try {
if (!hasTasks()) {
strategy = select(curDeadlineNanos);
}
} finally {
nextWakeupNanos.lazySet(AWAKE);
}
default:
}
} catch (IOException e) {
rebuildSelector0();
selectCnt = 0;
handleLoopException(e);
continue;
}
selectCnt++;
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
boolean ranTasks;
if (ioRatio == 100) {
try {
if (strategy > 0) {
processSelectedKeys();
}
} finally {
ranTasks = runAllTasks();
}
} else if (strategy > 0) {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
final long ioTime = System.nanoTime() - ioStartTime;
ranTasks = runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
} else {
ranTasks = runAllTasks(0);
}
if (ranTasks || strategy > 0) {
if (selectCnt > MIN_PREMATURE_SELECTOR_RETURNS && logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.",
selectCnt - 1, selector);
}
selectCnt = 0;
} else if (unexpectedSelectorWakeup(selectCnt)) {
selectCnt = 0;
}
} catch (CancelledKeyException e) {
if (logger.isDebugEnabled()) {
logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?",
selector, e);
}
} catch (Throwable t) {
handleLoopException(t);
}
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
processSelectedKeys()是处理任务的核心逻辑,来自于NioEventLoop的run()方法调用
private void processSelectedKeys() {
if (selectedKeys != null) {
processSelectedKeysOptimized();
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
}
private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
if (selectedKeys.isEmpty()) {
return;
}
Iterator<SelectionKey> i = selectedKeys.iterator();
for (;;) {
final SelectionKey k = i.next();
final Object a = k.attachment();
i.remove();
if (a instanceof AbstractNioChannel) {
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (!i.hasNext()) {
break;
}
if (needsToSelectAgain) {
selectAgain();
selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
break;
} else {
i = selectedKeys.iterator();
}
}
}
}
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) {
final EventLoop eventLoop;
try {
eventLoop = ch.eventLoop();
} catch (Throwable ignored) {
return;
}
if (eventLoop == this) {
unsafe.close(unsafe.voidPromise());
}
return;
}
try {
int readyOps = k.readyOps();
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
ch.unsafe().forceFlush();
}
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
其中读事件的处理
unsafe.read();
----------------------------------------------------------------------------
public final void read() {
final ChannelConfig config = config();
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
final ChannelPipeline pipeline = pipeline();
final ByteBufAllocator allocator = config.getAllocator();
final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
allocHandle.reset(config);
ByteBuf byteBuf = null;
boolean close = false;
try {
do {
byteBuf = allocHandle.allocate(allocator);
allocHandle.lastBytesRead(doReadBytes(byteBuf));
if (allocHandle.lastBytesRead() <= 0) {
byteBuf.release();
byteBuf = null;
close = allocHandle.lastBytesRead() < 0;
if (close) {
readPending = false;
}
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close, allocHandle);
} finally {
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
Bootstrap
引导,对应用程序进行配置,并让他运行起来的过程
1)配置
必选参数:group 、 channel、 handler(服务端 – childHandler)
group(): 指定一个到两个reactor
channel():指定channel工厂,反射的方式创建channel使用
handler():指定reactor的处理器,其中childHandler指定的是,服务端所接收到的客户端channel使用的处理器,而服务端的主reactor(bossGroup),已经默认添加了acceptor处理器,所以可以不指定
option():指定TCP相关的参数,以及netty自定义的参数
配置参数的过程,称之为初始化
2)运行
try {
ChannelFuture future = serverBootstrap.bind(8888).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
bind(),将服务端的channel绑定到端口号,然后接收客户端的连接,让整个netty运行起来
sync(),因为绑定事件是异步的,所以使用sync同步等待结果,换句话说,bind只触发了绑定端口的事件,需要使用sync等待事件执行的结果
future.channel().closeFuture().sync(),含义为,当通道被关闭时,才执行后续的操作,sync使当前线程执行到此处阻塞,以确保不执行后续的shutdown方法
3)源码
类声明
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
嵌套的泛型使用,可以达到,子类中返回子类本身的效果,具体如下:
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
init方法
工作内容
设置channel相关的选项参数
设置channel的属性键值对
添加对channel的IO事件处理器 (Acceptor角色)
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
}
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
Acceptor分析
功能:将主reactor接收到的客户端通道,传递给从reactor
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
final ChannelConfig config = ctx.channel().config();
if (config.isAutoRead()) {
config.setAutoRead(false);
ctx.channel().eventLoop().schedule(enableAutoReadTask, 1, TimeUnit.SECONDS);
}
ctx.fireExceptionCaught(cause);
}
Future和Promise
Future代表的是,一个还未完成的异步任务的执行结果。可以通过addListener方法,监听执行结果后进行相应的处理,此时它的状态可以分为未完成、已完成(成功、失败、主动取消)等
对Future而言,状态只能读取,无法更改,又出现了Promise,但是Promise只能更改一次
参照生活中的定额发票(Future)和机打发票(Promise)