8.1 介紹
DataBuffer
接口定義了在byte緩沖區(qū)上的抽象,引入它的原因是不是代替java.nio.ByteBuffer
, 是由于Netty
. Netty
不使用ByteBuffer
, 而是使用ByteBuf
來代替. Spring的DataBuffer
就是在ByteBuf
上的簡單抽象, 它也能用于非Netty
平臺(tái).
8.2 DataBufferFactory
DataBufferFactory
提供了分配新的數(shù)據(jù)緩沖區(qū)和包裝現(xiàn)有數(shù)據(jù)的功能.allocate
方法以一個(gè)默認(rèn)的給定容器分配一個(gè)新的數(shù)據(jù)緩沖區(qū). 雖然DataBuffer
會(huì)按需擴(kuò)大或收縮空間, 但是如果已知空間大小 ,則分配前給定空間大小是有好處的. wrap
方法包裝現(xiàn)有的ByteBuffer
或byte數(shù)組, 包裝不涉及分配, 它只是簡單的用一個(gè)DataBuffer
實(shí)現(xiàn)包裝給定的數(shù)據(jù).
DataBufferFactory
接口有兩個(gè)實(shí)現(xiàn):
-
NettyDataBufferFactory
: 在Netty
平臺(tái)上使用. -
DefaultDataBufferFactory
: 在其他平臺(tái)上使用.
8.3 DataBuffer接口
這個(gè)接口類似于ByteBuffer
接口, 但是它提供了一些與Netty的ByteBuf類似的功能.它提供了獨(dú)立的讀寫位置, 這與JDK的ByteBuffer
不同(它對讀和寫僅提供一個(gè)位置以及一個(gè)用于在兩個(gè)IO操作之間切換的flip()
操作).
0 <= read position <= write position <= capacity
當(dāng)從DataBuffer中讀取字節(jié)時(shí),讀寫的位置都會(huì)根據(jù)從緩沖區(qū)讀寫的數(shù)據(jù)量自動(dòng)更新.在寫數(shù)據(jù)時(shí),DataBuffer的容量也會(huì)自動(dòng)擴(kuò)展,就如同StringBuilder, ArrayList一樣.
另外, DataBuffer也提供了一些方法可以將其作為ByteBuffer, InputStream, 或OutputStream
來進(jìn)行操作.它還提供了確定給定byte位置的方法.
它也有兩個(gè)實(shí)現(xiàn):
- NettyDataBuffer: 應(yīng)用于Netty平臺(tái).
- DefaultDataBuffer: 應(yīng)用于其他平臺(tái).
8.3.1 PooledDataBuffer
PooledDataBuffer
擴(kuò)展了DataBuffer
, 提供了應(yīng)用計(jì)數(shù)的方法(池). retain
方法將引用計(jì)數(shù)加1, release
方法將引用計(jì)數(shù)減1, 當(dāng)計(jì)數(shù)值為0時(shí)會(huì)釋放緩沖內(nèi)存空間.這兩個(gè)方法都與引用計(jì)數(shù)有關(guān).
DataBufferUtils
類提供了操作引用計(jì)數(shù)的實(shí)用方法, 它們都以一個(gè)DataBuffer
實(shí)例作為參數(shù), 但僅當(dāng)參數(shù)為PooledDataBuffer
類型時(shí)才會(huì)調(diào)用retail
和release
方法.
通常, 訪問DataBuffer的最后一個(gè)組件負(fù)責(zé)釋放它, 在spring中,這有兩個(gè)組件可以釋放緩沖區(qū), 即decoders
和transports
, decoder負(fù)責(zé)將緩沖區(qū)的流轉(zhuǎn)換為其他類型, transport負(fù)責(zé)傳輸流(如HTTP消息), 如果你在分配數(shù)據(jù)緩沖區(qū)的過程中出現(xiàn)了異常, 此時(shí)你只能自己釋放它.
示例:
DataBufferFactory factory = ...
// 分配一個(gè)新的緩沖區(qū)
DataBuffer buffer = factory.allocateBuffer();
// 緩沖區(qū)是否應(yīng)該被釋放
boolean release = true;
try {
// 給緩沖區(qū)中寫入數(shù)據(jù), 它可能拋出異常, 所以要在finally中釋放它.
writeDataToBuffer(buffer);
putBufferInHttpBody(buffer);
// 如果沒有發(fā)生異常, 當(dāng)釋放標(biāo)志改為false,緩沖區(qū)將會(huì)作為通過網(wǎng)絡(luò)發(fā)送的HTTP body的一部分被釋放
release = false;
}
finally {
if (release) {
// 如果發(fā)生了異常,這個(gè)標(biāo)志仍為true, 緩沖區(qū)將被釋放.
DataBufferUtils.release(buffer);
}
}
private void writeDataToBuffer(DataBuffer buffer) throws IOException {
...
}
8.3.2 DataBufferUtils
DataBufferUtils包含了一些操作數(shù)據(jù)緩沖區(qū)的實(shí)用方法.參考相關(guān)文檔.
Codecs
org.springframework.core.codec
包提供了兩個(gè)主要抽象, 用于byte流與對象流之間的相互轉(zhuǎn)換.Encoder
接口的功能是將對象流編碼為數(shù)據(jù)緩沖區(qū)的輸出流, Decoder
與之相反, 它是將數(shù)據(jù)緩沖區(qū)的流轉(zhuǎn)換為對象流. 注意decoder
實(shí)例要考慮引用計(jì)數(shù).
spring提供了大量的默認(rèn)解編碼器, 能夠轉(zhuǎn)換字符串, ByteBuffer, byte數(shù)組.
在spring的響應(yīng)式框架中,解編碼器還被用來將請求body轉(zhuǎn)換為控制器參數(shù), 或?qū)⒎祷仡愋娃D(zhuǎn)換到response body中返回給客戶端.默認(rèn)的解編碼器在WebFluxConfigurationSuport
類中配置, 也可以通過這個(gè)類的configureHttpMessageCodecs
方法進(jìn)行修改.