在我的应用程序中,我在进一步传递之前计算有效负载的长度(由
ObjectMapper
生成的 JSON)。
为了实现这一点,我使用自定义
OutputStream
:
@Autowired
ObjectMapper objectMapper;
private int calculateContentLength(MyPayload payload) throws IOException {
var countingOutputStream = new CountingOutputStream();
objectMapper.writeValue(countingOutputStream, accounts);
return countingOutputStream.count;
}
private static class CountingOutputStream extends OutputStream {
private int count;
@Override
public void write(int b) {
count++;
}
@Override
public void write(byte[] b) {
count += b.length;
}
@Override
public void write(byte[] b, int off, int len) {
count += b.length;
}
}
这工作得很好,但是需要一些额外的时间和内存来进行反序列化(
write(byte[] b, int off, int len)
方法接收长度为8192的byte[]
)。
我想知道是否有其他更快的方法来实现这个?
如果您正在寻找一种更快、更节省内存的方法来计算 ObjectMapper 生成的 JSON 有效负载的长度,您可能需要考虑以下替代方案:
1。直接使用ObjectMapper
您可以将对象序列化为 byte[],然后获取其长度,而不是使用自定义 OutputStream:
private int calculateContentLength(MyPayload payload) throws IOException {
byte[] jsonBytes = objectMapper.writeValueAsBytes(payload);
return jsonBytes.length;
}
优点:
缺点:
2。使用流式传输方法
如果您需要有效处理大型负载并避免将所有内容加载到内存中,您可以使用 Jackson 的 JsonGenerator 以流式传输方式估计长度。这种方法更复杂,但对于大负载来说内存效率更高。
private int calculateContentLength(MyPayload payload) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JsonGenerator generator = objectMapper.getFactory().createGenerator(baos);
objectMapper.writeValue(generator, payload);
generator.close();
return baos.size();
}
优点:
缺点:
3.具有优化写入方法的自定义输出流
如果您仍然喜欢使用自定义OutputStream,您可以通过更有效地实现写入方法来优化它:
private static class CountingOutputStream extends OutputStream {
private long count;
@Override
public void write(int b) {
count++;
}
@Override
public void write(byte[] b) {
count += b.length;
}
@Override
public void write(byte[] b, int off, int len) {
count += len;
}
public long getCount() {
return count;
}
}
优点:
缺点:
总结
对于大多数情况,writeValueAsBytes 是最简单、最有效的方法。如果您正在处理非常大的有效负载并且需要最大限度地减少内存使用量,那么使用 JsonGenerator 的流式传输方法可能值得考虑。