主要分一下几点讲解:
1、ByteBuf结构
2、read、write、set方法
3、mark和reset方法
一、ByteBuf结构
我们找到ByteBuf源码,查看最前面的注释,有这样一段:
* <pre>
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | (CONTENT) | |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
* </pre>
在netty里面,有几个重要的指针:
1、readerIndex,0到readerindex这里就是不读的数据,也就是抛弃的数据;从readerIndex开始读数据。
2、writerIndex,readerIndex到writerIndex这里就是没有读的数据,也就是可读的内容;从writeIndex开始写数据。
3、capacity,writerIndex到capacity这段数据就是我们可以往里面写的空间
4、maxCapacity,其实这里应该还有个maxCapacity(可以看做是在capacity后面),capacity到maxCapacity这里,是这个Byte还可以扩展的空间。
二、read、write、set方法
我们找到ByteBuf的read方法,发现它居然有这么多种实现:
...
public abstract boolean readBoolean();
public abstract byte readByte();
public abstract short readUnsignedByte();
public abstract short readShort();
public abstract short readShortLE();
public abstract int readUnsignedShort();
public abstract int readUnsignedShortLE();
public abstract int readMedium();
....
当然这里之列举了一部分,netty会根据数据的大小选择合适的read方法。
write也不用说了:
...
public abstract ByteBuf writeBoolean(boolean value);
public abstract ByteBuf writeByte(int value);
public abstract ByteBuf writeShort(int value);
public abstract ByteBuf writeShortLE(int value);
...
set方法:
...
public abstract ByteBuf setBoolean(int index, boolean value);
public abstract ByteBuf setByte(int index, int value);
public abstract ByteBuf setShort(int index, int value);
public abstract ByteBuf setShortLE(int index, int value);
...
read和write是做什么的不用多解释,这里我们介绍以下set,其实也就是在特定的index开始的位置设置上特定的值,可以从index位置开始,设置多个。
三、mark和reset方法
这里先介绍以下,mark我标记在某个位置,执行read或者write之后指针会变化,我用reset就可以设置回去原来mark的位置了:
/**
* Marks the current {@code readerIndex} in this buffer. You can
* reposition the current {@code readerIndex} to the marked
* {@code readerIndex} by calling {@link #resetReaderIndex()}.
* The initial value of the marked {@code readerIndex} is {@code 0}.
*/
public abstract ByteBuf markReaderIndex();
/**
* Repositions the current {@code readerIndex} to the marked
* {@code readerIndex} in this buffer.
*
* @throws IndexOutOfBoundsException
* if the current {@code writerIndex} is less than the marked
* {@code readerIndex}
*/
public abstract ByteBuf resetReaderIndex();
/**
* Marks the current {@code writerIndex} in this buffer. You can
* reposition the current {@code writerIndex} to the marked
* {@code writerIndex} by calling {@link #resetWriterIndex()}.
* The initial value of the marked {@code writerIndex} is {@code 0}.
*/
public abstract ByteBuf markWriterIndex();
/**
* Repositions the current {@code writerIndex} to the marked
* {@code writerIndex} in this buffer.
*
* @throws IndexOutOfBoundsException
* if the current {@code readerIndex} is greater than the marked
* {@code writerIndex}
*/
public abstract ByteBuf resetWriterIndex();
看看源码的注释就能明白
四、其他API
在一个开始我们也介绍过这几个指针,看看注释,就知道这些方法的作用:
/**
* Returns the number of readable bytes which is equal to
* {@code (this.writerIndex - this.readerIndex)}.
*/
public abstract int readableBytes();
/**
* Returns the number of writable bytes which is equal to
* {@code (this.capacity - this.writerIndex)}.
*/
public abstract int writableBytes();
/**
* Returns the maximum possible number of writable bytes, which is equal to
* {@code (this.maxCapacity - this.writerIndex)}.
*/
public abstract int maxWritableBytes();
/**
* Returns {@code true}
* if and only if {@code (this.writerIndex - this.readerIndex)} is greater
* than {@code 0}.
*/
public abstract boolean isReadable();
/**
* Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements.
*/
public abstract boolean isReadable(int size);
/**
* Returns {@code true}
* if and only if {@code (this.capacity - this.writerIndex)} is greater
* than {@code 0}.
*/
public abstract boolean isWritable();
/**
* Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of
* elements.
*/
public abstract boolean isWritable(int size);
/**
* Sets the {@code readerIndex} and {@code writerIndex} of this buffer to
* {@code 0}.
* This method is identical to {@link #setIndex(int, int) setIndex(0, 0)}.
* <p>
* Please note that the behavior of this method is different
* from that of NIO buffer, which sets the {@code limit} to
* the {@code capacity} of the buffer.
*/
public abstract ByteBuf clear();
我们可以知道,ByteBuf的读写什么,其实就是不停地移动这些指针。初始的位置readerIndex和writerIndex的位置都是0。
五、AbstactByteBuf
首先我们查看一下这个类的关系图:
我们暂且不管下面的几个实现吧(下一篇再介绍),直接先看AbstractByteBuf,继承于ByteBuf,看这个类的源码的解释:
/**
* A skeletal implementation of a buffer.
*/
public abstract class AbstractByteBuf extends ByteBuf {
...
}
a skeletal implementation。对buffer也就是ByteBuf的一个骨架式的实现。阅读源码多了,我们都知道这个套路,abstract一般就是对接口的骨架式实现。
继续看:
int readerIndex;
int writerIndex;
private int markedReaderIndex;
private int markedWriterIndex;
private int maxCapacity;
前面介绍的那几个指针,都在这里体现出来了。
前面说过的maxCapacity:
protected AbstractByteBuf(int maxCapacity) {
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
}
this.maxCapacity = maxCapacity;
}
readableBytes()的实现:
@Override
public int readableBytes() {
return writerIndex - readerIndex;
}
writableBytes(),maxWritableBytes(),markReaderIndex(),resetReaderIndex()这几个不赘述,自行查看源码,简单。
然后我们看ByteBuf readerIndex(int readerIndex):
@Override
public ByteBuf readerIndex(int readerIndex) {
if (readerIndex < 0 || readerIndex > writerIndex) {
throw new IndexOutOfBoundsException(String.format(
"readerIndex: %d (expected: 0 <= readerIndex <= writerIndex(%d))", readerIndex, writerIndex));
}
this.readerIndex = readerIndex;
return this;
}
保证不越界,并且附上读指针。从这里我们开始留意到,ByteBuf很多都是返回this指针,方便链式调用。
看readByte():
@Override
public byte readByte() {
checkReadableBytes0(1);
int i = readerIndex;
byte b = _getByte(i);
readerIndex = i + 1;
return b;
}
我们看到,读的操作是委托到有一个下划线的_getByte(i)方法里面,别的readBool(),readInt()等这些方法,都是一个道理。
在这里,由于byte是一个字节,所以readerIndex是i+1;
如果是readInt():
@Override
public int readInt() {
checkReadableBytes0(4);
int v = _getInt(readerIndex);
readerIndex += 4;
return v;
}
int 是个字节,那么就是加4。
至于下划线方法的实现,会委托给每种ByteBuf最终子类的实现,有各自的方法,这就关系到各个ByteBuf实现的区别了,后续的文章会继续讲解。(readableBytes(),writableBytes(),maxWritableBytes(),markReaderIndex(),resetReaderIndex()这些方法能够在这里实现是因为它们和底层的读写没有关系)
AbstractByteBuf通过对这些接口对外能够提供丰富的功能,这里是不是对抽象有了深一点的理解呢?抽象出接口,并实现一部分功能,具体的实现由方法里面的子类实现的方法去实现。
wirteByte方法也是一样的:
@Override
public ByteBuf writeByte(int value) {
ensureAccessible();
ensureWritable0(1);
_setByte(writerIndex++, value);
return this;
}
后面的方法,自行查看源码,不赘述了。
关于ByteBuf的分类,请听下回分解