【翻译 Spring 5.0.4.RELEASE】8. Data Buffers and Codecs

8. Data Buffers and Codecs

8.1. Introduction

DataBuffer接口定义了一个字节缓冲区的抽象。 引入它的主要原因是Netty,而不是使用标准的java.nio.ByteBuffer。 Netty不使用ByteBuffer,而是提供ByteBuf作为替代。 Spring的DataBuffer是ByteBuf的一个简单抽象,也可以在非Netty平台上使用(即Servlet 3.1+)。

8.2. DataBufferFactory

DataBufferFactory提供分配新数据缓冲区的功能,以及包装现有数据。 分配方法分配一个新的数据缓冲区,具有默认或给定容量。 尽管DataBuffer的实现随需求增长和缩减,但如果知道的话,提前提供容量效率更高。 包装方法装饰现有的ByteBuffer或字节数组。 包装不涉及分配:它只是用DataBuffer实现装饰给定的数据。

DataBufferFactory有两种实现方式:NettyDataBufferFactory,用于在Netty平台上使用,例如Reactor Netty。 另一个实现DefaultDataBufferFactory用于其他平台,如Servlet 3.1+服务器。

8.3. The DataBuffer interface

DataBuffer接口与ByteBuffer类似,但具有许多优点。 与Netty的ByteBuf类似,DataBuffer抽象提供独立的读写位置。 这与JDK的ByteBuffer不同,它只显示一个读取和写入位置,另一个单独的flip()操作用于在两个I / O操作之间切换。 一般而言,读取位置,写入位置和容量的下列不变量保持不变:

`0` <= _read position_ <= _write position_ <= _capacity_

从DataBuffer读取字节时,读取位置会根据从缓冲区中读取的数据量自动更新。 同样,当向DataBuffer写入字节时,写入位置将使用写入缓冲区的数据量进行更新。 另外,在写入数据时,DataBuffer的容量会自动扩展,就像StringBuilder,ArrayList和类似的类型一样。

除了上面提到的读写功能外,DataBuffer还具有方法来查看ByteBuffer,InputStream或OutputStream的缓冲区(片段)。 此外,它还提供了确定给定字节索引的方法。

DataBuffer有两个实现:NettyDataBuffer,用于Netty平台,如Reactor Netty。 另一个实现DefaultDataBuffer用于其他平台,如Servlet 3.1+服务器。

8.3.1. PooledDataBuffer

PooledDataBuffer是DataBuffer的扩展,它增加了引用计数的方法。 保留方法将引用计数增加1。 释放方法将计数减1,并在计数达到0时释放缓冲区的内存。这两种方法都与引用计数相关,后者将解释这种机制。

请注意,DataBufferUtils为释放和保留池化数据缓冲区提供了有用的实用方法。 这些方法采用普通的DataBuffer作为参数,但只有在传递的数据缓冲区是PooledDataBuffer的实例时才调用retain或release。

Reference Counting

引用计数不是Java中常见的技术;它在其他编程语言(如Object C和C ++)中更为常见。引用计数本身并不复杂:它基本上涉及跟踪应用于对象的引用的数量。 PooledDataBuffer的引用计数从1开始,通过调用retain保持增加,并通过调用release来减少。只要缓冲区的引用计数大于0,缓冲区就不会被释放。当数字减少到0时,实例将被释放。在实践中,这意味着由缓冲区捕获的保留内存将被返回到内存池,准备用于未来的分配。

通常,访问DataBuffer的最后一个组件负责释放它。使用Spring,有两种释放缓冲区的组件:解码器和传输。解码器负责将缓冲流转换为其他类型(请参阅下面的编解码器),并且传输负责通过网络边界发送缓冲区,通常作为HTTP消息。这意味着如果您将数据缓冲区分配给出站HTTP消息(即客户端请求或服务器端响应),则不需要发布它们。这个规则的另一个后果是,如果你分配的数据缓冲区不会在本体中结束,比如由于抛出的异常,你将不得不自己释放它们。下面的代码片段显示了处理抛出异常的方法时典型的DataBuffer使用场景:

DataBufferFactory factory = ...
DataBuffer buffer = factory.allocateBuffer(); 
boolean release = true; 
try {
    writeDataToBuffer(buffer); 
    putBufferInHttpBody(buffer);
    release = false; 
}
finally {
    if (release) {
        DataBufferUtils.release(buffer); 
    }
}

private void writeDataToBuffer(DataBuffer buffer) throws IOException { 
    ...
}

一个新的缓冲区被分配。
布尔标志指示是否应释放分配的缓冲区。
该示例方法将数据加载到缓冲区中。 请注意,该方法可能会抛出IOException,因此需要释放缓冲区的finally块。
如果没有发生异常,我们将释放标志切换为false,因为缓冲区现在将作为发送HTTP主体的一部分发布。
如果发生异常,该标志仍设置为true,并且缓冲区将在此处释放。

8.3.2. DataBufferUtils

DataBufferUtils包含对数据缓冲区进行操作的各种实用程序方法。 它包含从InputStream或NIO通道读取DataBuffer对象的Flux的方法,以及将数据缓冲区Flux写入OutputStream或Channel的方法。 DataBufferUtils还公开了在普通DataBuffer实例上运行的保留和释放方法(因此不需要将其转换为PooledDataBuffer)。

此外,DataBufferUtils公开了合成,它将一组数据缓冲区合并为一个。 例如,可以使用此方法将整个HTTP主体转换为单个缓冲区(以及来自该缓冲区的字符串或InputStream)。 这在处理较老的阻塞API时特别有用。 但是,请注意,这会将整个机体放在记忆中,因此比纯粹的流式传输解决方案需要更多的内存。

Codecs

org.springframework.core.codec包包含两个主要抽象,用于将字节流转换为对象流,反之亦然。编码器是一种策略接口,它将对象流编码为数据缓冲区的输出流。解码器做了相反的事情:它将一串数据缓冲区变成一个对象流。请注意,解码器实例需要考虑引用计数。

Spring带有大量的默认编解码器,能够从/到String,ByteBuffer,字节数组以及支持编组库的编解码器(如杰克逊2.9+支持非阻塞解析)的编解码器。使用Spring WebFlux的上下文,使用编解码器将请求主体转换为@RequestMapping参数,或者将返回类型转换为发送回客户端的响应主体。默认的编解码器是在WebFluxConfigurationSupport类中配置的,并且可以通过在从该类继承时重写configureHttpMessageCodecs来轻松进行更改。有关在WebFlux中使用编解码器的更多信息,请参阅本节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值