From eec22f5072011259bee02cd23cd6d0692f1cb187 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 29 Mar 2016 15:51:00 +0200 Subject: [PATCH] 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 --- .../HttpInvokerServiceExporter.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java index 0e85a7bcc4..654cc6ca8f 100644 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java +++ b/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. + *

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 SPR-14040 + */ + class FlushGuardedOutputStream extends FilterOutputStream { + public FlushGuardedOutputStream(OutputStream out) { + super(out); + } + + @Override + public void flush() throws IOException { + // Do nothing + } + } + }