EDIT Hier ist eine verbesserte Version, die viel robuster erscheinen und JDK-Klassen verwenden. Rufen Sie einfach close()
vor der Wiederverwendung auf.
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();
}
}
}
Dies ermöglicht es den ganzen Strom in dem Puffer zu lesen, durch die mark
-Integer.MAXVALUE
zwicken. Dies stellt auch sicher, dass die Quelle bei der ersten nahe bei der Freigabe befindlichen OS-Ressource ordnungsgemäß geschlossen ist.
Alte Antwort
Wie Sie nicht sicher, dass die tatsächliche Umsetzung der InputStream
Unterstützung Marke sein kann (markSupported()
). Sie sollten den Eingabedatenstrom selbst in einer ersten Anwendung besser zwischenspeichern.
Für exemple in einem 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());
}
}
Der Caching-Input-Stream ist ein naiver Ansatz zur Eingabe-Stream-Caching ist es ähnlich wie Ihr Ansatz:
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();
}
}
Diese Implementierung ist naiv verschiedene Art und Weise, kann es in dem folgenden Bereich verbessert werden, und wahrscheinlich mehr:
- Chec k
markSupported
auf dem ursprünglichen Strom
- Sie den Heap nicht verwenden, um den im Cache gespeicherten Eingabestrom zu speichern, würde dies den Druck auf dem GC
- Cache unbegrenzt zu vermeiden, ist zur Zeit kann dies eine gute Besserung sein, zumindest das gleiche verwenden Grenzen als Ihr http-Server.
Verweis auf Interceptors und Filter unter [link] (https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-2rd-edition/en/part1/chapter12 /reader_and_writer_interceptors.html) – Gautam