編輯這是一個改進版本,它看起來更加健壯並且使用JDK類。在重用之前請調用close()
。
public class CachingInputStream extends BufferedInputStream {
public CachingInputStream(InputStream source) {
super(new PostCloseProtection(source));
super.mark(Integer.MAX_VALUE);
}
@Override
public synchronized void close() throws IOException {
if (!((PostCloseProtection) in).decoratedClosed) {
in.close();
}
super.reset();
}
private static class PostCloseProtection extends InputStream {
private volatile boolean decoratedClosed = false;
private final InputStream source;
public PostCloseProtection(InputStream source) {
this.source = source;
}
@Override
public int read() throws IOException {
return decoratedClosed ? -1 : source.read();
}
@Override
public int read(byte[] b) throws IOException {
return decoratedClosed ? -1 : source.read(b);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return decoratedClosed ? -1 : source.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return decoratedClosed ? 0 : source.skip(n);
}
@Override
public int available() throws IOException {
return source.available();
}
@Override
public void close() throws IOException {
decoratedClosed = true;
source.close();
}
@Override
public void mark(int readLimit) {
source.mark(readLimit);
}
@Override
public void reset() throws IOException {
source.reset();
}
@Override
public boolean markSupported() {
return source.markSupported();
}
}
}
這允許在緩衝器讀取整個流,通過調整mark
到Integer.MAXVALUE
。這也確保源在第一次關閉時被正確關閉以釋放OS資源。
老回答
正如你不能確定實際執行的InputStream
支持標記(markSupported()
)的。您最好在第一次評估中緩存輸入流本身。
對於爲例在ContainerRequestFilter
:
@Component
@Provider
@PreMatching
@Priority(1)
public class ReadSomethingInPayloadFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext request) throws IOException {
CachingInputStream entityStream = new CachingInputStream(request.getEntityStream());
readPayload(entityStream);
request.setEntityStream(entityStream.getCachedInputStream());
}
}
緩存輸入流是一個很自然的做法輸入流緩存,它的方式類似於你的方法:
class CachingInputStream extends InputStream {
public static final int END_STREAM = -1;
private final InputStream is;
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
public CachingInputStream(InputStream is) {
this.is = is;
}
public InputStream getCachedInputStream() {
return new ByteArrayInputStream(baos.toByteArray());
}
@Override
public int read() throws IOException {
int result = is.read();
// Avoid rewriting the end char (-1) otherwise it will be considered as a real char.
if (result != END_STREAM)
baos.write(result);
return result;
}
@Override
public int available() throws IOException {
return is.available();
}
@Override
public void close() throws IOException {
is.close();
}
}
這個實現是幼稚各種方式,它可以在以下方面進行改進,可能更多:
- Chec在原始流
- ķ
markSupported
不要使用堆存儲緩存輸入流,這將避免壓力對GC
- Cache是無界目前這可能是一個不錯的改進,至少是使用相同的綁定爲你的http服務器。
請參閱[link]上的攔截器和過濾器部分(https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-2rd-edition/en/part1/chapter12 /reader_and_writer_interceptors.html) – Gautam