spring-core-8 数据缓冲区和编码器
8.1 介绍
DataBuffer
接口定义了在byte缓冲区上的抽象,引入它的原因是不是代替java.nio.ByteBuffer
, 是由于Netty
. Netty
不使用ByteBuffer
, 而是使用ByteBuf
来代替. Spring的DataBuffer
就是在ByteBuf
上的简单抽象, 它也能用于非Netty
平台.
8.2 DataBufferFactory
DataBufferFactory
提供了分配新的数据缓冲区和包装现有数据的功能.allocate
方法以一个默认的给定容器分配一个新的数据缓冲区. 虽然DataBuffer
会按需扩大或收缩空间, 但是如果已知空间大小 ,则分配前给定空间大小是有好处的. wrap
方法包装现有的ByteBuffer
或byte数组, 包装不涉及分配, 它只是简单的用一个DataBuffer
实现包装给定的数据.
DataBufferFactory
接口有两个实现:
-
NettyDataBufferFactory
: 在Netty
平台上使用. -
DefaultDataBufferFactory
: 在其他平台上使用.
8.3 DataBuffer接口
这个接口类似于ByteBuffer
接口, 但是它提供了一些与Netty的ByteBuf类似的功能.它提供了独立的读写位置, 这与JDK的ByteBuffer
不同(它对读和写仅提供一个位置以及一个用于在两个IO操作之间切换的flip()
操作).
0 <= read position <= write position <= capacity
当从DataBuffer中读取字节时,读写的位置都会根据从缓冲区读写的数据量自动更新.在写数据时,DataBuffer的容量也会自动扩展,就如同StringBuilder, ArrayList一样.
另外, DataBuffer也提供了一些方法可以将其作为ByteBuffer, InputStream, 或OutputStream
来进行操作.它还提供了确定给定byte位置的方法.
它也有两个实现:
- NettyDataBuffer: 应用于Netty平台.
- DefaultDataBuffer: 应用于其他平台.
8.3.1 PooledDataBuffer
PooledDataBuffer
扩展了DataBuffer
, 提供了应用计数的方法(池). retain
方法将引用计数加1, release
方法将引用计数减1, 当计数值为0时会释放缓冲内存空间.这两个方法都与引用计数有关.
DataBufferUtils
类提供了操作引用计数的实用方法, 它们都以一个DataBuffer
实例作为参数, 但仅当参数为PooledDataBuffer
类型时才会调用retail
和release
方法.
通常, 访问DataBuffer的最后一个组件负责释放它, 在spring中,这有两个组件可以释放缓冲区, 即decoders
和transports
, decoder负责将缓冲区的流转换为其他类型, transport负责传输流(如HTTP消息), 如果你在分配数据缓冲区的过程中出现了异常, 此时你只能自己释放它.
示例:
DataBufferFactory factory = ...
// 分配一个新的缓冲区
DataBuffer buffer = factory.allocateBuffer();
// 缓冲区是否应该被释放
boolean release = true;
try {
// 给缓冲区中写入数据, 它可能抛出异常, 所以要在finally中释放它.
writeDataToBuffer(buffer);
putBufferInHttpBody(buffer);
// 如果没有发生异常, 当释放标志改为false,缓冲区将会作为通过网络发送的HTTP body的一部分被释放
release = false;
}
finally {
if (release) {
// 如果发生了异常,这个标志仍为true, 缓冲区将被释放.
DataBufferUtils.release(buffer);
}
}
private void writeDataToBuffer(DataBuffer buffer) throws IOException {
...
}
8.3.2 DataBufferUtils
DataBufferUtils包含了一些操作数据缓冲区的实用方法.参考相关文档.
Codecs
org.springframework.core.codec
包提供了两个主要抽象, 用于byte流与对象流之间的相互转换.Encoder
接口的功能是将对象流编码为数据缓冲区的输出流, Decoder
与之相反, 它是将数据缓冲区的流转换为对象流. 注意decoder
实例要考虑引用计数.
spring提供了大量的默认解编码器, 能够转换字符串, ByteBuffer, byte数组.
在spring的响应式框架中,解编码器还被用来将请求body转换为控制器参数, 或将返回类型转换到response body中返回给客户端.默认的解编码器在WebFluxConfigurationSuport
类中配置, 也可以通过这个类的configureHttpMessageCodecs
方法进行修改.