Skip to content

Commit eec22f5

Browse files
committed
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
1 parent b947bfe commit eec22f5

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.remoting.httpinvoker;
1818

19+
import java.io.FilterOutputStream;
1920
import java.io.IOException;
2021
import java.io.InputStream;
2122
import java.io.ObjectInputStream;
@@ -169,7 +170,8 @@ protected void writeRemoteInvocationResult(
169170
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
170171
throws IOException {
171172

172-
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os));
173+
ObjectOutputStream oos =
174+
createObjectOutputStream(new FlushGuardedOutputStream(decorateOutputStream(request, response, os)));
173175
try {
174176
doWriteRemoteInvocationResult(result, oos);
175177
}
@@ -195,4 +197,25 @@ protected OutputStream decorateOutputStream(
195197
return os;
196198
}
197199

200+
/**
201+
* Decorate an OutputStream to guard against {@code flush()} calls, which
202+
* are turned into no-ops.
203+
* <p>Because {@link ObjectOutputStream#close()} will in fact flush/drain
204+
* the underlying stream twice, this {@link FilterOutputStream} will
205+
* guard against individual flush calls. Multiple flush calls can lead
206+
* to performance issues, since writes aren't gathered as they should be.
207+
*
208+
* @see <a href="https://jira.spring.io/browse/SPR-14040">SPR-14040</a>
209+
*/
210+
class FlushGuardedOutputStream extends FilterOutputStream {
211+
public FlushGuardedOutputStream(OutputStream out) {
212+
super(out);
213+
}
214+
215+
@Override
216+
public void flush() throws IOException {
217+
// Do nothing
218+
}
219+
}
220+
198221
}

0 commit comments

Comments
 (0)