上一章我们介绍了 ByteBuf 功能,这一章我们将讲解它重要的一个子类 AbstractByteBuf,它实现了 ByteBuf 中很多通用功能,这样子类就不需要各自实现了。
在
netty中很多模块都是这样的,会有一个Abstract类实现模块的基础功能。
一. 重要属性
1.1 静态属性
1.1.1 checkAccessible
是否需要检查访问权限,默认是 true,是一个静态属性,所有 ByteBuf 实例一样。
/**
* Used internally by {@link AbstractByteBuf#ensureAccessible()} to try to guard
* against using the buffer after it was released (best-effort).
*/
boolean isAccessible() {
return refCnt() != 0;
}
/**
* Should be called by every method that tries to access the buffers content to check
* if the buffer was released before.
*/
protected final void ensureAccessible() {
if (checkAccessible && !isAccessible()) {
throw new IllegalReferenceCountException(0);
}
}
当 checkAccessible 为 true 的时候,才会调用 isAccessible() 方法,判断访问权限。
可以通过
io.netty.buffer.checkAccessible和io.netty.buffer.bytebuf.checkAccessible两个配置项设置。
private static final String LEGACY_PROP_CHECK_ACCESSIBLE = "io.netty.buffer.bytebuf.checkAccessible";
private static final String PROP_CHECK_ACCESSIBLE = "io.netty.buffer.checkAccessible";
static final boolean checkAccessible; // accessed from CompositeByteBuf
static {
if (SystemPropertyUtil.contains(PROP_CHECK_ACCESSIBLE)) {
checkAccessible = SystemPropertyUtil.getBoolean(PROP_CHECK_ACCESSIBLE, true);
} else {
checkAccessible = SystemPropertyUtil.getBoolean(LEGACY_PROP_CHECK_ACCESSIBLE, true);
}
......
}
1.1.2 checkBounds
是否需要检查操作是否超出缓存区 ByteBuf 界限,默认是 true,是一个静态属性,所有 ByteBuf 实例一样。
可以通过
io.netty.buffer.checkBounds配置项设置
private static final boolean checkBounds;
static {
......
checkBounds = SystemPropertyUtil.getBoolean(PROP_CHECK_BOUNDS, true);
......
}
1.1.3 leakDetector
检查缓存区 ByteBuf 是否存在内存泄露情况。是一个静态属性,所有 ByteBuf 实例共享。
static final ResourceLeakDetector<ByteBuf> leakDetector =
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ByteBuf.class);
1.2 成员属性
-
readerIndex: 读索引 -
writerIndex: 写索引 -
markedReaderIndex: 标记读索引 -
markedWriterIndex: 标记写索引 -
maxCapacity: 缓存区最大容量
你会发现,这里没有代表缓存区当前容量的属性,因为缓存区当前容量在不同类型缓存区实现中,表示形式是不一样的,所以这里就没有这个属性。
二. 构造方法
AbstractByteBuf 只有一个构造方法
protected AbstractByteBuf(int maxCapacity) {
checkPositiveOrZero(maxCapacity, "maxCapacity");
this.maxCapacity = maxCapacity;
}
也就是说缓存区必须设置它的最大容量 maxCapacity。
三. 重要方法
3.1 索引和标记索引相关
-
checkIndexBounds: 检查是否超出缓存区界限private static void checkIndexBounds(final int readerIndex, final int writerIndex, final int capacity) { if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity) { throw new IndexOutOfBoundsException(String.format( "readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))", readerIndex, writerIndex, capacity)); } } -
readerIndex()和readerIndex(int readerIndex): 获取和设置读索引readerIndex@Override public int readerIndex() { return readerIndex; } @Override public ByteBuf readerIndex(int readerIndex) { if (checkBounds) { checkIndexBounds(readerIndex, writerIndex, capacity()); } this.readerIndex = readerIndex; return this; } -
writerIndex()和writerIndex(int writerIndex): 获取和设置写索引writerIndex@Override public int writerIndex() { return writerIndex; } @Override public ByteBuf writerIndex(int writerIndex) { if (checkBounds) { checkIndexBounds(readerIndex, writerIndex, capacity()); } this.writerIndex = writerIndex; return this; } -
setIndex(int readerIndex, int writerIndex): 同时设置读索引readerIndex和写索引writerIndex@Override public ByteBuf setIndex(int readerIndex, int writerIndex) { if (checkBounds) { checkIndexBounds(readerIndex, writerIndex, capacity()); } setIndex0(readerIndex, writerIndex); return this; } -
clear(): 清除读索引readerIndex和写索引writerIndex,相当于setIndex(0, 0)@Override public ByteBuf clear() { readerIndex = writerIndex = 0; return this; } -
markReaderIndex()和resetReaderIndex(): 标记和重置读索引readerIndex。@Override public ByteBuf markReaderIndex() { markedReaderIndex = readerIndex; return this; } @Override public ByteBuf resetReaderIndex() { readerIndex(markedReaderIndex); return this; } -
markWriterIndex()和resetWriterIndex(): 标记和重置写索引writerIndex。@Override public ByteBuf markWriterIndex() { markedWriterIndex = writerIndex; return this; } @Override public ByteBuf resetWriterIndex() { writerIndex(markedWriterIndex); return this; } -
discardReadBytes(): 这个方法会将可读区域readable bytes数据移动到开头,让可写区域writable bytes变得更多,它也会改变读写索引。@Override public ByteBuf discardReadBytes() { // 如果读索引是0,那么就不需要移动,直接返回 if (readerIndex == 0) { ensureAccessible(); return this; } if (readerIndex != writerIndex) { // readerIndex != writerIndex,说明还有可读数据,那么就需要将这些可读数据移动到开头。 // 这里取巧了,直接调用 ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) 方法,源缓存区就是自己 setBytes(0, this, readerIndex, writerIndex - readerIndex); // 移动后写索引的值 writerIndex -= readerIndex; // 但是要调整一下标记索引的大小 adjustMarkers(readerIndex); // 读索引的值设置为 0 readerIndex = 0; } else { // 如果 readerIndex == writerIndex,说明没有可读内容了,就不涉及数据移动了。 // 那么直接将 readerIndex 和 writerIndex 设置为 0 ensureAccessible(); // 但是要调整一下标记索引的大小 adjustMarkers(readerIndex); writerIndex = readerIndex = 0; } return this; }分为三种情况:
-
readerIndex == 0说明可读数据就在开头,不需要移动,直接返回。 -
readerIndex == writerIndex说明没有可读数据了,那么也不需要移动数据了,直接将读写索引都设置为0,顺便修改一下标记索引的大小。 -
readerIndex != writerIndex说明还有可读数据,那么就需要将这些可读数据移动到开头,通过调用setBytes(int index, ByteBuf src, int srcIndex, int length)方法来移动数据,然后将读索引设置为0,写索引设置为writerIndex - readerIndex, 顺便修改一下标记索引的大小。
-
-
discardSomeReadBytes():这个方法不像discardReadBytes()方法,必须将可读区域readable bytes移动到开头,它会判断读索引的位置,来决定是否将可读区域移动到开头。所以它也有可能改变读写索引。@Override public ByteBuf discardSomeReadBytes() { // 只有读索引大于 0,才有可能需要移动 if (readerIndex > 0) { // 当 readerIndex == writerIndex,说明没有可读内容了,不需要数据移动 // 那么直接将 readerIndex 和 writerIndex 设置为 0 if (readerIndex == writerIndex) { ensureAccessible(); // 要调整一下标记索引的大小 adjustMarkers(readerIndex); writerIndex = readerIndex = 0; return this; } // 当读索引的值大于或者等于 缓存区容量的一半时,才进行数据移动 if (readerIndex >= capacity() >>> 1) { // 直接调用 ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) 方法,源缓存区就是自己 setBytes(0, this, readerIndex, writerIndex - readerIndex); // 移动后写索引的值 writerIndex -= readerIndex; // 调整一下标记索引的大小 adjustMarkers(readerIndex); // 读索引的值设置为 0 readerIndex = 0; return this; } } ensureAccessible(); return this; }这个方法与
discardReadBytes()方法相比较,你会发现,唯一的不同就是它只会当读索引的值大于或者等于缓存区容量的一半时,才进行数据移动。
3.2 容量相关
-
maxCapacity()和maxCapacity(int maxCapacity): 获取和设置缓存区最大容量maxCapacity。 -
isReadable()和isReadable(int numBytes): 缓存区是否有足够可读区域readable bytes。@Override public boolean isReadable() { return writerIndex > readerIndex; } @Override public boolean isReadable(int numBytes) { return writerIndex - readerIndex >= numBytes; } -
isWritable()和isWritable(int numBytes): 缓存区是否有足够可写区域writable bytes。@Override public boolean isWritable() { return capacity() > writerIndex; } @Override public boolean isWritable(int numBytes) { return capacity() - writerIndex >= numBytes; } -
readableBytes(): 缓存区可读区域readable bytes的大小。@Override public int readableBytes() { return writerIndex - readerIndex; } -
writableBytes(): 缓存区可写区域writable bytes的大小。@Override public int writableBytes() { return capacity() - writerIndex; } -
maxWritableBytes(): 缓存区最大可写区域writable bytes的大小。@Override public int maxWritableBytes() { return maxCapacity() - writerIndex; } -
ensureWritable(int minWritableBytes): 扩展缓存区容量。@Override public ByteBuf ensureWritable(int minWritableBytes) { ensureWritable0(checkPositiveOrZero(minWritableBytes, "minWritableBytes")); return this; } final void ensureWritable0(int minWritableBytes) { final int writerIndex = writerIndex(); // 目标容量 final int targetCapacity = writerIndex + minWritableBytes; // using non-short-circuit & to reduce branching - this is a hot path and targetCapacity should rarely overflow // 如果目标容量小于当前容量,那么不需要扩展,直接返回。 // targetCapacity >= 0 是为了防止目标容量溢出了,超过 int 类型最大值 if (targetCapacity >= 0 & targetCapacity <= capacity()) { ensureAccessible(); return; } if (checkBounds && (targetCapacity < 0 || targetCapacity > maxCapacity)) { ensureAccessible(); throw new IndexOutOfBoundsException(String.format( "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s", writerIndex, minWritableBytes, maxCapacity, this)); } // Normalize the target capacity to the power of 2. // 最快能够获取的最大可写区域大小,它的大小在 writableBytes() <= maxFastWritableBytes() <= markWriterIndex() final int fastWritable = maxFastWritableBytes(); // 如果 fastWritable 大小足够,那么新容量就是 writerIndex + fastWritable; // 否则就是用 ByteBufAllocator 的 calculateNewCapacity 计算出新容量。 // 特别注意,新的容量一定是 2的幂。 int newCapacity = fastWritable >= minWritableBytes ? writerIndex + fastWritable : alloc().calculateNewCapacity(targetCapacity, maxCapacity); // 设置缓存区新容量 capacity(newCapacity); }注意一下几点:
- 当目标容量
targetCapacity小于或者等于当前缓存区容量capacity(),那就直接返回。 - 当目标容量
targetCapacity超出缓存区最大容量maxCapacity,那么新容量newCapacity的值就是maxCapacity,这是alloc().calculateNewCapacity(targetCapacity, maxCapacity)方法的实现。 - 新容量
newCapacity一定是2的幂数。
- 当目标容量
-
int ensureWritable(int minWritableBytes, boolean force): 也是扩展缓存区容量。@Override public int ensureWritable(int minWritableBytes, boolean force) { ensureAccessible(); checkPositiveOrZero(minWritableBytes, "minWritableBytes"); // minWritableBytes 在当前缓存区可写区域内,直接返回 if (minWritableBytes <= writableBytes()) { return 0; } // 最大容量 final int maxCapacity = maxCapacity(); // 读索引 final int writerIndex = writerIndex(); // 待写字节大小 minWritableBytes,超出缓存区最大可写区域 `maxCapacity - writerIndex` if (minWritableBytes > maxCapacity - writerIndex) { // 非强制或者当前容量就是最大容量 if (!force || capacity() == maxCapacity) { // 返回 1 return 1; } // 将缓存区容量设置成最大容量maxCapacity capacity(maxCapacity); return 3; } // 扩展缓存区大小 int fastWritable = maxFastWritableBytes(); int newCapacity = fastWritable >= minWritableBytes ? writerIndex + fastWritable : alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity); // Adjust to the new capacity. capacity(newCapacity); return 2; }扩展缓存区只会分为四种情况:
- 待写字节
minWritableBytes小于或者等于缓存区可写区域大小writableBytes(),不需要扩展容量,直接返回0。 - 待写字节
minWritableBytes小于或者等于缓存区最大可写区域大小maxCapacity - writerIndex,能够正常扩展容量,返回2。 - 待写字节
minWritableBytes超出缓存区最大可写区域maxCapacity - writerIndex, 不能正常扩展容量,那么分为两种情况:如果非强制(!force)或者当前容量就是最大容量时返回1,否则就将缓存区容量设置成最大容量并返回3。也就是1和3的区别,1没有改变缓存区容量,而3重新设置的缓存区容量。
- 待写字节
3.3 get 系列方法
我们知道 get 系列方法都从还钱指定索引位置读取数据。
3.3.1 获取基本数据类型的方法
首先我们讲解一下有符号和无符号类型的区别,因为 netty 提供了很多获取无符号基本数据类型的方法。
- 对于有符号数据类型来说,它的最高位表示正负,即
0表示正数,1表示负数。而对于无符号数据类型来说,它只表示正数,最高位也是数据内容。例如对于byte类型数据,有符号byte范围就是-128 -->127,而无符号byte范围就是0 --> 255。- 所以将有符号数据变成无符号数据也很简单,就是将自身字节数据全部保留。例如获取无符号
byte类型数据,就是(short) (getByte(index) & 0xFF)。- 注意:
0xFF是一个int类型数据,那么getByte(index)的值也要由byte提升到int类型,然后才能计算,而类型提升时,如果是正数,那么高位全部补零,如果是负数,那么高位全部补1。而0xFF正好是高三个字节全是0,地位一个字节数据全是1,因此就正好保存了getByte(index)byte字节中全部数据。
-
获取
byte类型数据@Override public byte getByte(int index) { checkIndex(index); return _getByte(index); } protected abstract byte _getByte(int index); @Override public boolean getBoolean(int index) { return getByte(index) != 0; } @Override public short getUnsignedByte(int index) { return (short) (getByte(index) & 0xFF); }- 通过
getBoolean(int index),我们知道boolean类型在缓存区存储的是一个byte字节,0表示false, 非零就是true。 -
_getByte(int index)方法是由子类实现的,不同类型的ByteBuf实现不一样。 - 必须通过
checkIndex(index)方法,检查是否越界。 - 通过
(getByte(index) & 0xFF)获取无符号byte值。
- 通过
-
获取
short类型数据@Override public short getShort(int index) { checkIndex(index, 2); return _getShort(index); } protected abstract short _getShort(int index); @Override public short getShortLE(int index) { checkIndex(index, 2); return _getShortLE(index); } protected abstract short _getShortLE(int index); @Override public int getUnsignedShort(int index) { return getShort(index) & 0xFFFF; } @Override public int getUnsignedShortLE(int index) { return getShortLE(index) & 0xFFFF; }- 有两个需要子类复写的方法
_getShort(int index)和_getShortLE(int index)。 - 必须通过
checkIndex(index, 2)方法,检查是否越界。 - 通过
& 0xFFFF获取无符号的short类型。
- 有两个需要子类复写的方法
-
获取
Medium类型数据
这是一个三个字节的整形数据,java中没有对应类型,只能用int类型表示。@Override public int getUnsignedMedium(int index) { checkIndex(index, 3); return _getUnsignedMedium(index); } protected abstract int _getUnsignedMedium(int index); @Override public int getUnsignedMediumLE(int index) { checkIndex(index, 3); return _getUnsignedMediumLE(index); } protected abstract int _getUnsignedMediumLE(int index); @Override public int getMedium(int index) { int value = getUnsignedMedium(index); // 三字节最高位是不是 `1` if ((value & 0x800000) != 0) { // 通过 `0xff000000` 将 value 值转换成负数 value |= 0xff000000; } return value; } @Override public int getMediumLE(int index) { int value = getUnsignedMediumLE(index); // 三字节最高位是不是 `1` if ((value & 0x800000) != 0) { // 通过 `0xff000000` 将 value 值转换成负数 value |= 0xff000000; } return value; }- 有两个需要子类复写的方法
_getUnsignedMedium(int index)和_getUnsignedMediumLE(int index)。 - 必须通过
checkIndex(index, 3)方法,检查是否越界。 - 你会发现不一样的点,
Medium类型数据,直接获取的是无符号Medium类型,有符号Medium类型反而要做特殊处理。即判断三字节最高位是不是1(即(value & 0x800000) != 0), 然后转成负数value |= 0xff000000。主要是因为java是没有三个字节的整形数据的。
- 有两个需要子类复写的方法
-
获取
int类型数据@Override public int getInt(int index) { checkIndex(index, 4); return _getInt(index); } protected abstract int _getInt(int index); @Override public int getIntLE(int index) { checkIndex(index, 4); return _getIntLE(index); } protected abstract int _getIntLE(int index); @Override public long getUnsignedInt(int index) { return getInt(index) & 0xFFFFFFFFL; } @Override public long getUnsignedIntLE(int index) { return getIntLE(index) & 0xFFFFFFFFL; }- 有两个需要子类复写的方法
_getInt(int index)和_getIntLE(int index)。 - 必须通过
checkIndex(index, 4)方法,检查是否越界。 - 通过
& 0xFFFFFFFFL获取无符号的short类型。注意0xFFFFFFFFL是一个long类型。
- 有两个需要子类复写的方法
-
获取
long类型数据@Override public long getLong(int index) { checkIndex(index, 8); return _getLong(index); } protected abstract long _getLong(int index); @Override public long getLongLE(int index) { checkIndex(index, 8); return _getLongLE(index); } protected abstract long _getLongLE(int index);- 有两个需要子类复写的方法
_getLong(int index)和_getLongLE(int index)。 - 必须通过
checkIndex(index, 8)方法,检查是否越界。 -
long类型不需要无符号long类型了
- 有两个需要子类复写的方法
-
其他基础类型方法
@Override public char getChar(int index) { return (char) getShort(index); } @Override public float getFloat(int index) { return Float.intBitsToFloat(getInt(index)); } public float getFloatLE(int index) { return Float.intBitsToFloat(getIntLE(index)); } @Override public double getDouble(int index) { return Double.longBitsToDouble(getLong(index)); } public double getDoubleLE(int index) { return Double.longBitsToDouble(getLongLE(index)); }- 你会发现单浮点型
float数据是通过int类型存储的,双浮点型double数据是通过long类型存储的。
- 你会发现单浮点型
3.3.2 其他方法
-
getBytes(int index, byte[] dst)@Override public ByteBuf getBytes(int index, byte[] dst) { getBytes(index, dst, 0, dst.length); return this; } -
getBytes(int index, ByteBuf dst)和getBytes(int index, ByteBuf dst, int length)@Override public ByteBuf getBytes(int index, ByteBuf dst) { getBytes(index, dst, dst.writableBytes()); return this; } @Override public ByteBuf getBytes(int index, ByteBuf dst, int length) { getBytes(index, dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); return this; }会改变目标缓存区
dst的写索引writerIndex的值。 -
getCharSequence(int index, int length, Charset charset)@Override public CharSequence getCharSequence(int index, int length, Charset charset) { if (CharsetUtil.US_ASCII.equals(charset) || CharsetUtil.ISO_8859_1.equals(charset)) { // ByteBufUtil.getBytes(...) will return a new copy which the AsciiString uses directly return new AsciiString(ByteBufUtil.getBytes(this, index, length, true), false); } return toString(index, length, charset); }
3.4 set 系列方法
3.4.1 设置基本数据类型的方法
- 设置
byte类型数据@Override public ByteBuf setByte(int index, int value) { checkIndex(index); _setByte(index, value); return this; } protected abstract void _setByte(int index, int value); @Override public ByteBuf setBoolean(int index, boolean value) { setByte(index, value? 1 : 0); return this; }- 需要子类复写
_setByte(int index, int value)方法 - 注意,虽然设置
byte类型数据,但是传递的值value却是int类型。
- 需要子类复写
- 设置
short类型数据@Override public ByteBuf setShort(int index, int value) { checkIndex(index, 2); _setShort(index, value); return this; } protected abstract void _setShort(int index, int value); @Override public ByteBuf setShortLE(int index, int value) { checkIndex(index, 2); _setShortLE(index, value); return this; } protected abstract void _setShortLE(int index, int value); @Override public ByteBuf setChar(int index, int value) { setShort(index, value); return this; }- 需要子类复写
_setShort(int index, int value)和_setShortLE(int index, int value)方法 - 注意,虽然设置
short类型数据,但是传递的值value却是int类型。 -
char类型也是用short类型数据存储的。
- 需要子类复写
- 设置
medium类型数据@Override public ByteBuf setMedium(int index, int value) { checkIndex(index, 3); _setMedium(index, value); return this; } protected abstract void _setMedium(int index, int value); @Override public ByteBuf setMediumLE(int index, int value) { checkIndex(index, 3); _setMediumLE(index, value); return this; } protected abstract void _setMediumLE(int index, int value);- 需要子类复写
_setMedium(int index, int value)和_setMediumLE(int index, int value)方法 - 注意,虽然设置
medium类型数据,但是传递的值value却是int类型。
- 需要子类复写
- 设置
int类型数据@Override public ByteBuf setInt(int index, int value) { checkIndex(index, 4); _setInt(index, value); return this; } protected abstract void _setInt(int index, int value); @Override public ByteBuf setIntLE(int index, int value) { checkIndex(index, 4); _setIntLE(index, value); return this; } protected abstract void _setIntLE(int index, int value); @Override public ByteBuf setFloat(int index, float value) { setInt(index, Float.floatToRawIntBits(value)); return this; }- 需要子类复写
_setInt(int index, int value)和_setIntLE(int index, int value)方法 - 单精度浮点型
float数据使用int类型存储的。
- 需要子类复写
- 设置
long类型数据@Override public ByteBuf setLong(int index, long value) { checkIndex(index, 8); _setLong(index, value); return this; } protected abstract void _setLong(int index, long value); @Override public ByteBuf setLongLE(int index, long value) { checkIndex(index, 8); _setLongLE(index, value); return this; } protected abstract void _setLongLE(int index, long value); @Override public ByteBuf setDouble(int index, double value) { setLong(index, Double.doubleToRawLongBits(value)); return this; }- 需要子类复写
_setLong(int index, long value)和_setLongLE(int index, long value)方法 - 双精度浮点型
double数据使用long类型存储的。
- 需要子类复写
3.4.2 其他方法
-
setBytes(int index, byte[] src)@Override public ByteBuf setBytes(int index, byte[] src) { setBytes(index, src, 0, src.length); return this; } -
setBytes(int index, ByteBuf src)和setBytes(int index, ByteBuf src, int length)@Override public ByteBuf setBytes(int index, ByteBuf src) { setBytes(index, src, src.readableBytes()); return this; } @Override public ByteBuf setBytes(int index, ByteBuf src, int length) { checkIndex(index, length); ObjectUtil.checkNotNull(src, "src"); if (checkBounds) { checkReadableBounds(src, length); } setBytes(index, src, src.readerIndex(), length); src.readerIndex(src.readerIndex() + length); return this; }- 会改变源缓存区
src的读索引readerIndex的值。
- 会改变源缓存区
-
setZero(int index, int length)@Override public ByteBuf setZero(int index, int length) { if (length == 0) { return this; } // 检查边界 checkIndex(index, length); // 计算 length/8 的值,因为 long 类型是8个字节,优先使用 long 设置 int nLong = length >>> 3; // 不足 8 的值 int nBytes = length & 7; // 先使用 long 来设置 for (int i = nLong; i > 0; i --) { _setLong(index, 0); index += 8; } // 如果正好等于4,那么直接用一个 int 类型就可以了 if (nBytes == 4) { _setInt(index, 0); // Not need to update the index as we not will use it after this. } else if (nBytes < 4) { // 不足 4 个字节,那么就直接使用 byte 字节设置,这里就不用 short再来一层了 for (int i = nBytes; i > 0; i --) { _setByte(index, (byte) 0); index ++; } } else { _setInt(index, 0); index += 4; // 不足 4 个字节,那么就直接使用 byte 字节设置,这里就不用 short再来一层了 for (int i = nBytes - 4; i > 0; i --) { _setByte(index, (byte) 0); index ++; } } return this; }就是将缓存区从
index起length长度的区域的值都设置成0,这路使用了技巧,优先使用long类型设置,不足8个字节的部分,使用int类型 和byte类型设置。
3.5 read 系列方法
3.5.1 读取基本数据类型的方法
- 读取
byte类型数据private void checkReadableBytes0(int minimumReadableBytes) { ensureAccessible(); if (checkBounds && readerIndex > writerIndex - minimumReadableBytes) { throw new IndexOutOfBoundsException(String.format( "readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s", readerIndex, minimumReadableBytes, writerIndex, this)); } } @Override public byte readByte() { checkReadableBytes0(1); int i = readerIndex; byte b = _getByte(i); readerIndex = i + 1; return b; } @Override public boolean readBoolean() { return readByte() != 0; } @Override public short readUnsignedByte() { return (short) (readByte() & 0xFF); }- 通过
checkReadableBytes0(1)方法检查是否越界。 - 获取完数据之后,将读索引
readerIndex值增加1。
- 通过
- 读取
short类型数据@Override public short readShort() { checkReadableBytes0(2); short v = _getShort(readerIndex); readerIndex += 2; return v; } @Override public short readShortLE() { checkReadableBytes0(2); short v = _getShortLE(readerIndex); readerIndex += 2; return v; } @Override public int readUnsignedShort() { return readShort() & 0xFFFF; } @Override public int readUnsignedShortLE() { return readShortLE() & 0xFFFF; } @Override public char readChar() { return (char) readShort(); }- 通过
checkReadableBytes0(2)方法检查是否越界。 - 获取完数据之后,将读索引
readerIndex值增加2。 - 字符
char类型是通过short类型读取的。
- 通过
- 读取
medium类型数据@Override public int readMedium() { int value = readUnsignedMedium(); if ((value & 0x800000) != 0) { value |= 0xff000000; } return value; } @Override public int readMediumLE() { int value = readUnsignedMediumLE(); if ((value & 0x800000) != 0) { value |= 0xff000000; } return value; } @Override public int readUnsignedMedium() { checkReadableBytes0(3); int v = _getUnsignedMedium(readerIndex); readerIndex += 3; return v; } @Override public int readUnsignedMediumLE() { checkReadableBytes0(3); int v = _getUnsignedMediumLE(readerIndex); readerIndex += 3; return v; }- 通过
checkReadableBytes0(3)方法检查是否越界。 - 获取完数据之后,将读索引
readerIndex值增加3。
- 通过
- 读取
int类型数据@Override public int readInt() { checkReadableBytes0(4); int v = _getInt(readerIndex); readerIndex += 4; return v; } @Override public int readIntLE() { checkReadableBytes0(4); int v = _getIntLE(readerIndex); readerIndex += 4; return v; } @Override public long readUnsignedInt() { return readInt() & 0xFFFFFFFFL; } @Override public long readUnsignedIntLE() { return readIntLE() & 0xFFFFFFFFL; } @Override public float readFloat() { return Float.intBitsToFloat(readInt()); }- 通过
checkReadableBytes0(4)方法检查是否越界。 - 获取完数据之后,将读索引
readerIndex值增加4。 - 单精度浮点数
float数据,是通过int类型转换的。
- 通过
- 读取
long类型数据@Override public long readLong() { checkReadableBytes0(8); long v = _getLong(readerIndex); readerIndex += 8; return v; } @Override public long readLongLE() { checkReadableBytes0(8); long v = _getLongLE(readerIndex); readerIndex += 8; return v; } @Override public double readDouble() { return Double.longBitsToDouble(readLong()); }- 通过
checkReadableBytes0(8)方法检查是否越界。 - 获取完数据之后,将读索引
readerIndex值增加8。 - 双精度浮点数
double数据,是通过long类型转换的。
- 通过
3.5.2 读取一小段缓存区
-
readBytes(int length)@Override public ByteBuf readBytes(int length) { checkReadableBytes(length); if (length == 0) { return Unpooled.EMPTY_BUFFER; } // 创建新的缓存区,初始容量initialCapacity就是 length,最大容量是maxCapacity ByteBuf buf = alloc().buffer(length, maxCapacity); // 通过 writeBytes 方法将本缓存区从readerIndex 起 length长度的数据写入到新创建的缓存区buf buf.writeBytes(this, readerIndex, length); // 增加读索引的值 readerIndex += length; // 返回新创建的缓存区 return buf; }这个将本缓存区的一段内容复制到新创建的缓存区中,它们不共享数据,不会互相影响。
-
readSlice(int length)和readRetainedSlice(int length)@Override public ByteBuf readSlice(int length) { checkReadableBytes(length); ByteBuf slice = slice(readerIndex, length); readerIndex += length; return slice; } @Override public ByteBuf readRetainedSlice(int length) { checkReadableBytes(length); ByteBuf slice = retainedSlice(readerIndex, length); readerIndex += length; return slice; }通过
slice和retainedSlice方法,获取本缓存区一段内容的新缓存区,但是这个新缓存区与本缓存区共享内存,也就说更改本缓冲区对应区域的内容,那么新缓存区的内容也会改变。
3.5.3 读取数据到字节数组
@Override
public ByteBuf readBytes(byte[] dst) {
readBytes(dst, 0, dst.length);
return this;
}
@Override
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
checkReadableBytes(length);
getBytes(readerIndex, dst, dstIndex, length);
readerIndex += length;
return this;
}
最终还是通过
getBytes(int index, byte[] dst, int dstIndex, int length)方法实现。不过它增加了读索引readerIndex的值。
3.5.4 读取数据到其他缓存区ByteBuf
@Override
public ByteBuf readBytes(ByteBuf dst) {
readBytes(dst, dst.writableBytes());
return this;
}
@Override
public ByteBuf readBytes(ByteBuf dst, int length) {
if (checkBounds) {
if (length > dst.writableBytes()) {
throw new IndexOutOfBoundsException(String.format(
"length(%d) exceeds dst.writableBytes(%d) where dst is: %s", length, dst.writableBytes(), dst));
}
}
readBytes(dst, dst.writerIndex(), length);
dst.writerIndex(dst.writerIndex() + length);
return this;
}
@Override
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
checkReadableBytes(length);
getBytes(readerIndex, dst, dstIndex, length);
readerIndex += length;
return this;
}
- 最后通过调用
getBytes(int index, ByteBuf dst, int dstIndex, int length)方法实现- 如果从目标缓存区
dst的写索引writerIndex处,那么就增加目标缓存区dst的写索引值,因此前两个方法会增加目标缓存区dst的写索引值。- 它们都增加本缓存区读索引值。
3.5.5 读取数据到 NIO缓存区ByteBuffer
@Override
public ByteBuf readBytes(ByteBuffer dst) {
int length = dst.remaining();
checkReadableBytes(length);
getBytes(readerIndex, dst);
readerIndex += length;
return this;
}
3.5.6 读取数据到IO流
@Override
public int readBytes(GatheringByteChannel out, int length)
throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length);
readerIndex += readBytes;
return readBytes;
}
@Override
public int readBytes(FileChannel out, long position, int length)
throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, position, length);
readerIndex += readBytes;
return readBytes;
}
@Override
public ByteBuf readBytes(OutputStream out, int length) throws IOException {
checkReadableBytes(length);
getBytes(readerIndex, out, length);
readerIndex += length;
return this;
}
3.5.7 跳过一段区域
@Override
public ByteBuf skipBytes(int length) {
checkReadableBytes(length);
readerIndex += length;
return this;
}
3.6 write 系列方法
所有 write 方法都通过 ensureWritable0 方法来确保有足够的写入空间
,并且写入之后都会增加写索引 writerIndex 的值。
3.6.1 写入基本数据类型的方法
- 写入
byte类型数据
@Override
public ByteBuf writeBoolean(boolean value) {
writeByte(value ? 1 : 0);
return this;
}
@Override
public ByteBuf writeByte(int value) {
ensureWritable0(1);
_setByte(writerIndex++, value);
return this;
}
- 写入
short类型数据@Override public ByteBuf writeShort(int value) { ensureWritable0(2); _setShort(writerIndex, value); writerIndex += 2; return this; } @Override public ByteBuf writeShortLE(int value) { ensureWritable0(2); _setShortLE(writerIndex, value); writerIndex += 2; return this; } @Override public ByteBuf writeChar(int value) { writeShort(value); return this; } - 写入
medium类型数据@Override public ByteBuf writeMedium(int value) { ensureWritable0(3); _setMedium(writerIndex, value); writerIndex += 3; return this; } @Override public ByteBuf writeMediumLE(int value) { ensureWritable0(3); _setMediumLE(writerIndex, value); writerIndex += 3; return this; } - 写入
int类型数据@Override public ByteBuf writeInt(int value) { ensureWritable0(4); _setInt(writerIndex, value); writerIndex += 4; return this; } @Override public ByteBuf writeIntLE(int value) { ensureWritable0(4); _setIntLE(writerIndex, value); writerIndex += 4; return this; } @Override public ByteBuf writeFloat(float value) { writeInt(Float.floatToRawIntBits(value)); return this; } - 写入
long类型数据@Override public ByteBuf writeLong(long value) { ensureWritable0(8); _setLong(writerIndex, value); writerIndex += 8; return this; } @Override public ByteBuf writeLongLE(long value) { ensureWritable0(8); _setLongLE(writerIndex, value); writerIndex += 8; return this; } @Override public ByteBuf writeDouble(double value) { writeLong(Double.doubleToRawLongBits(value)); return this; }
3.6.2 将字节数组的数据写入到缓存区
@Override
public ByteBuf writeBytes(byte[] src) {
writeBytes(src, 0, src.length);
return this;
}
@Override
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
ensureWritable(length);
setBytes(writerIndex, src, srcIndex, length);
writerIndex += length;
return this;
}
3.6.3 将其他缓存区ByteBuf数据写入到缓存区
@Override
public ByteBuf writeBytes(ByteBuf src) {
writeBytes(src, src.readableBytes());
return this;
}
@Override
public ByteBuf writeBytes(ByteBuf src, int length) {
if (checkBounds) {
checkReadableBounds(src, length);
}
writeBytes(src, src.readerIndex(), length);
src.readerIndex(src.readerIndex() + length);
return this;
}
@Override
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
ensureWritable(length);
setBytes(writerIndex, src, srcIndex, length);
writerIndex += length;
return this;
}
前两个方法会增加源缓存区
src读索引readerIndex的值。
3.6.4 将NIO 缓存区ByteBuffer的数据写入到缓存区
@Override
public ByteBuf writeBytes(ByteBuffer src) {
int length = src.remaining();
ensureWritable0(length);
setBytes(writerIndex, src);
writerIndex += length;
return this;
}
3.6.5 从输入流中读取数据写入到缓存区
@Override
public int writeBytes(InputStream in, int length)
throws IOException {
ensureWritable(length);
int writtenBytes = setBytes(writerIndex, in, length);
if (writtenBytes > 0) {
writerIndex += writtenBytes;
}
return writtenBytes;
}
@Override
public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
ensureWritable(length);
int writtenBytes = setBytes(writerIndex, in, length);
if (writtenBytes > 0) {
writerIndex += writtenBytes;
}
return writtenBytes;
}
@Override
public int writeBytes(FileChannel in, long position, int length) throws IOException {
ensureWritable(length);
int writtenBytes = setBytes(writerIndex, in, position, length);
if (writtenBytes > 0) {
writerIndex += writtenBytes;
}
return writtenBytes;
}
返回值表示写入缓存区的数据大小。
3.7 搜索
3.7.1 简单搜索
-
indexOf(int fromIndex, int toIndex, byte value)@Override public int indexOf(int fromIndex, int toIndex, byte value) { if (fromIndex <= toIndex) { return ByteBufUtil.firstIndexOf(this, fromIndex, toIndex, value); } return ByteBufUtil.lastIndexOf(this, fromIndex, toIndex, value); }当
fromIndex <= toIndex是升序搜索,反之就是降序搜索。
搜索范围,如果是升序,那么就是fromIndex(包括)到toIndex(排除);如果是降序,那么就是fromIndex(排除)到toIndex(包括),因为这个时候fromIndex的值比toIndex大。因此就是小的值会被包括,大的值会被排除。 -
bytesBefore()系列方法@Override public int bytesBefore(byte value) { return bytesBefore(readerIndex(), readableBytes(), value); } @Override public int bytesBefore(int length, byte value) { checkReadableBytes(length); return bytesBefore(readerIndex(), length, value); } @Override public int bytesBefore(int index, int length, byte value) { int endIndex = indexOf(index, index + length, value); if (endIndex < 0) { return -1; } return endIndex - index; }- 最终通过
indexOf方法来实现的。 - 它只能升序查找。
- 最终通过
3.7.2 复杂搜索
-
升序复杂搜索
@Override public int forEachByte(ByteProcessor processor) { ensureAccessible(); try { return forEachByteAsc0(readerIndex, writerIndex, processor); } catch (Exception e) { PlatformDependent.throwException(e); return -1; } } @Override public int forEachByte(int index, int length, ByteProcessor processor) { checkIndex(index, length); try { return forEachByteAsc0(index, index + length, processor); } catch (Exception e) { PlatformDependent.throwException(e); return -1; } } int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception { // 升序遍历 for (; start < end; ++start) { // 当 processor.process 返回false,表示查找到了,返回查找到的位置 if (!processor.process(_getByte(start))) { return start; } } // -1 表示查找不到 return -1; }注意当
processor.process方法返回false,表示查找到了。 -
降序复杂搜索
@Override public int forEachByteDesc(ByteProcessor processor) { ensureAccessible(); try { return forEachByteDesc0(writerIndex - 1, readerIndex, processor); } catch (Exception e) { PlatformDependent.throwException(e); return -1; } } @Override public int forEachByteDesc(int index, int length, ByteProcessor processor) { checkIndex(index, length); try { return forEachByteDesc0(index + length - 1, index, processor); } catch (Exception e) { PlatformDependent.throwException(e); return -1; } } int forEachByteDesc0(int rStart, final int rEnd, ByteProcessor processor) throws Exception { // 降序遍历 for (; rStart >= rEnd; --rStart) { // 当 processor.process 返回false,表示查找到了,返回查找到的位置 if (!processor.process(_getByte(rStart))) { return rStart; } } // -1 表示查找不到 return -1; }
3.8 复制缓存区
@Override
public ByteBuf copy() {
return copy(readerIndex, readableBytes());
}
最后调用
copy(readerIndex, readableBytes())方法,交给子类实现。
3.9 派生的缓冲区
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new UnpooledDuplicatedByteBuf(this);
}
@Override
public ByteBuf retainedDuplicate() {
return duplicate().retain();
}
@Override
public ByteBuf slice() {
return slice(readerIndex, readableBytes());
}
@Override
public ByteBuf retainedSlice() {
return slice().retain();
}
@Override
public ByteBuf slice(int index, int length) {
ensureAccessible();
return new UnpooledSlicedByteBuf(this, index, length);
}
@Override
public ByteBuf retainedSlice(int index, int length) {
return slice(index, length).retain();
}
3.10 转换成 ByteBuffer
@Override
public ByteBuffer nioBuffer() {
return nioBuffer(readerIndex, readableBytes());
}
@Override
public ByteBuffer[] nioBuffers() {
return nioBuffers(readerIndex, readableBytes());
}
这实现了这两个方法,剩余方法交给具体子类实现。







网友评论