From fe2108b8232bf56cee1fc612efa74791c228ac79 Mon Sep 17 00:00:00 2001 From: "Francisco A. Lozano" Date: Wed, 14 Jan 2015 21:02:52 +0100 Subject: [PATCH 1/2] Improve Netty4ClientHttpRequestFactory configurability and memory usage. --- .../http/client/Netty4ClientHttpRequest.java | 10 ++- .../Netty4ClientHttpRequestFactory.java | 81 ++++++++++++++++++- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequest.java index 92ea05d32018..a82aebe38e76 100644 --- a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequest.java @@ -24,8 +24,8 @@ import java.util.concurrent.ExecutionException; import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; -import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; @@ -51,9 +51,11 @@ * @since 4.1.2 */ class Netty4ClientHttpRequest extends AbstractAsyncClientHttpRequest implements ClientHttpRequest { + + public static final int INITIAL_REQUEST_BUFFER_SIZE = 512; private final Bootstrap bootstrap; - + private final URI uri; private final HttpMethod method; @@ -61,11 +63,11 @@ class Netty4ClientHttpRequest extends AbstractAsyncClientHttpRequest implements private final ByteBufOutputStream body; - public Netty4ClientHttpRequest(Bootstrap bootstrap, URI uri, HttpMethod method, int maxRequestSize) { + public Netty4ClientHttpRequest(Bootstrap bootstrap, ByteBufAllocator byteBufAllocator, URI uri, HttpMethod method, int maxRequestSize) { this.bootstrap = bootstrap; this.uri = uri; this.method = method; - this.body = new ByteBufOutputStream(Unpooled.buffer(maxRequestSize)); + this.body = new ByteBufOutputStream(byteBufAllocator.buffer(INITIAL_REQUEST_BUFFER_SIZE, maxRequestSize)); } diff --git a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java index fc3f5783ec45..94792e33f41d 100644 --- a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java @@ -20,7 +20,10 @@ import java.net.URI; import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; @@ -54,14 +57,48 @@ public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory, */ public static final int DEFAULT_MAX_REQUEST_SIZE = 1024 * 1024 * 10; + /** + * The default maximum header size + * @see #setMaxHeaderSize(int) + * @see HttpClientCodec#HttpClientCodec() + */ + public static final int DEFAULT_MAX_HEADER_SIZE = 8192; + + /** + * The default initial line length. + * @see #setInitialLineLength(int) + * @see HttpClientCodec#HttpClientCodec() + */ + public static final int DEFAULT_INITIAL_LINE_LENGTH = 4096; + + /** + * The default max chunk size. + * @see #setMaxChunkSize(int) + * @see HttpClientCodec#HttpClientCodec() + */ + public static final int DEFAULT_MAX_CHUNK_SIZE = 8192; + + /** + * The default byte-buf allocator. + * @see UnpooledByteBufAllocator#DEFAULT + */ + public static final ByteBufAllocator DEFAULT_BYTE_BUF_ALLOCATOR = UnpooledByteBufAllocator.DEFAULT; private final EventLoopGroup eventLoopGroup; private final boolean defaultEventLoopGroup; private int maxRequestSize = DEFAULT_MAX_REQUEST_SIZE; + + private int maxHeaderSize = DEFAULT_MAX_HEADER_SIZE; + + private int initialLineLength = DEFAULT_INITIAL_LINE_LENGTH; + + private int maxChunkSize = DEFAULT_MAX_CHUNK_SIZE; private SslContext sslContext; + + private ByteBufAllocator byteBufAllocator = DEFAULT_BYTE_BUF_ALLOCATOR; private volatile Bootstrap bootstrap; @@ -91,13 +128,48 @@ public Netty4ClientHttpRequestFactory(EventLoopGroup eventLoopGroup) { /** - * Set the default maximum request size. + * Set the maximum request size. *

By default this is set to {@link #DEFAULT_MAX_REQUEST_SIZE}. * @see HttpObjectAggregator#HttpObjectAggregator(int) */ public void setMaxRequestSize(int maxRequestSize) { this.maxRequestSize = maxRequestSize; } + + /** + * Set the maximum header size. + *

By default this is set to {@link #DEFAULT_MAX_HEADER_SIZE}. + * @see HttpClientCodec#HttpClientCodec(int, int, int) + */ + public void setMaxHeaderSize(int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + } + + /** + * Set the initial line length. + *

By default this is set to {@link #DEFAULT_INITIAL_LINE_LENGTH}. + * @see HttpClientCodec#HttpClientCodec(int, int, int) + */ + public void setInitialLineLength(int initialLineLength) { + this.initialLineLength = initialLineLength; + } + + /** + * Set the maximum chunk size. + *

By default this is set to {@link #DEFAULT_MAX_CHUNK_SIZE}. + * @see HttpClientCodec#HttpClientCodec(int, int, int) + */ + public void setMaxChunkSize(int maxChunkSize) { + this.maxChunkSize = maxChunkSize; + } + + /** + * Set the ByteBuf allocator used by the requests. + * @see ByteBufAllocator + */ + public void setByteBufAllocator(ByteBufAllocator byteBufAllocator) { + this.byteBufAllocator = byteBufAllocator; + } /** * Set the SSL context. When configured it is used to create and insert an @@ -111,6 +183,9 @@ public void setSslContext(SslContext sslContext) { private Bootstrap getBootstrap() { if (this.bootstrap == null) { Bootstrap bootstrap = new Bootstrap(); + if(byteBufAllocator!=null) { + bootstrap.option(ChannelOption.ALLOCATOR, byteBufAllocator); + } bootstrap.group(this.eventLoopGroup).channel(NioSocketChannel.class) .handler(new ChannelInitializer() { @Override @@ -119,7 +194,7 @@ protected void initChannel(SocketChannel channel) throws Exception { if (sslContext != null) { pipeline.addLast(sslContext.newHandler(channel.alloc())); } - pipeline.addLast(new HttpClientCodec()); + pipeline.addLast(new HttpClientCodec(initialLineLength, maxHeaderSize, maxChunkSize)); pipeline.addLast(new HttpObjectAggregator(maxRequestSize)); } }); @@ -145,7 +220,7 @@ public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) } private Netty4ClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) { - return new Netty4ClientHttpRequest(getBootstrap(), uri, httpMethod, this.maxRequestSize); + return new Netty4ClientHttpRequest(getBootstrap(), byteBufAllocator, uri, httpMethod, this.maxRequestSize); } From 6c673ac62b99e48cb3d2e1cc4ca286a6f9718967 Mon Sep 17 00:00:00 2001 From: "Francisco A. Lozano" Date: Wed, 14 Jan 2015 21:33:06 +0100 Subject: [PATCH 2/2] Correct ByteBufAllocator null handling. --- .../http/client/Netty4ClientHttpRequestFactory.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java index 94792e33f41d..5436dbbb8c2c 100644 --- a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java @@ -168,7 +168,12 @@ public void setMaxChunkSize(int maxChunkSize) { * @see ByteBufAllocator */ public void setByteBufAllocator(ByteBufAllocator byteBufAllocator) { - this.byteBufAllocator = byteBufAllocator; + if(byteBufAllocator==null) { + this.byteBufAllocator = DEFAULT_BYTE_BUF_ALLOCATOR; + } + else { + this.byteBufAllocator = byteBufAllocator; + } } /** @@ -183,9 +188,7 @@ public void setSslContext(SslContext sslContext) { private Bootstrap getBootstrap() { if (this.bootstrap == null) { Bootstrap bootstrap = new Bootstrap(); - if(byteBufAllocator!=null) { - bootstrap.option(ChannelOption.ALLOCATOR, byteBufAllocator); - } + bootstrap.option(ChannelOption.ALLOCATOR, byteBufAllocator); bootstrap.group(this.eventLoopGroup).channel(NioSocketChannel.class) .handler(new ChannelInitializer() { @Override