Avoid duplicate flush when closing outputstream

Prior to this commit, the `HttpInvokerServiceExporter` would close
its `ObjectOutputStream`, which itself issues duplicate flushes on the
underlying `OutputStream`. Duplicate flushes can lead to multiple,
separate TCP packets where those should be gathered writes.

This commit wraps the underying stream with a decorator that guards
against flush calls that are duplicated with the one done in `close`.

Issue: SPR-14040
master
Brian Clozel 9 years ago
parent b947bfe8e9
commit eec22f5072
  1. 27
      spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.remoting.httpinvoker;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
@ -169,7 +170,8 @@ public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExpor
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
throws IOException {
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os));
ObjectOutputStream oos =
createObjectOutputStream(new FlushGuardedOutputStream(decorateOutputStream(request, response, os)));
try {
doWriteRemoteInvocationResult(result, oos);
}
@ -195,4 +197,25 @@ public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExpor
return os;
}
/**
* Decorate an OutputStream to guard against {@code flush()} calls, which
* are turned into no-ops.
* <p>Because {@link ObjectOutputStream#close()} will in fact flush/drain
* the underlying stream twice, this {@link FilterOutputStream} will
* guard against individual flush calls. Multiple flush calls can lead
* to performance issues, since writes aren't gathered as they should be.
*
* @see <a href="https://jira.spring.io/browse/SPR-14040">SPR-14040</a>
*/
class FlushGuardedOutputStream extends FilterOutputStream {
public FlushGuardedOutputStream(OutputStream out) {
super(out);
}
@Override
public void flush() throws IOException {
// Do nothing
}
}
}

Loading…
Cancel
Save