diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 96c50f2e7fb..f0f8769c786 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -402,7 +402,7 @@ public class ServerProperties return this.tomcat; } - private Jetty getJetty() { + public Jetty getJetty() { return this.jetty; } @@ -950,11 +950,43 @@ public class ServerProperties } - private static class Jetty { + public static class Jetty { + + /** + * Number of acceptor threads to use. + */ + private Integer acceptors; + + /** + * Number of selector threads to use. + */ + private Integer selectors; + + public Integer getAcceptors() { + return this.acceptors; + } + + public void setAcceptors(Integer acceptors) { + this.acceptors = acceptors; + } + + public Integer getSelectors() { + return this.selectors; + } + + public void setSelectors(Integer selectors) { + this.selectors = selectors; + } void customizeJetty(ServerProperties serverProperties, JettyEmbeddedServletContainerFactory factory) { factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); + if (this.acceptors != null) { + factory.setAcceptors(this.acceptors); + } + if (this.selectors != null) { + factory.setSelectors(this.selectors); + } if (serverProperties.getMaxHttpHeaderSize() > 0) { customizeMaxHttpHeaderSize(factory, serverProperties.getMaxHttpHeaderSize()); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 1676c205658..81e8b4f26cd 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -64,6 +64,7 @@ import static org.mockito.Mockito.verify; * @author Phillip Webb * @author Eddú Meléndez * @author Quinten De Swaef + * @author Venil Noronha */ public class ServerPropertiesTests { @@ -260,6 +261,30 @@ public class ServerPropertiesTests { assertThat(this.properties.getMaxHttpHeaderSize()).isEqualTo(9999); } + @Test + public void testCustomizePostSize() throws Exception { + Map map = new HashMap(); + map.put("server.maxHttpPostSize", "9999"); + bindProperties(map); + assertThat(this.properties.getMaxHttpPostSize()).isEqualTo(9999); + } + + @Test + public void testCustomizeJettyAcceptors() throws Exception { + Map map = new HashMap(); + map.put("server.jetty.acceptors", "10"); + bindProperties(map); + assertThat(this.properties.getJetty().getAcceptors()).isEqualTo(10); + } + + @Test + public void testCustomizeJettySelectors() throws Exception { + Map map = new HashMap(); + map.put("server.jetty.selectors", "10"); + bindProperties(map); + assertThat(this.properties.getJetty().getSelectors()).isEqualTo(10); + } + @Test public void testCustomizeTomcatMinSpareThreads() throws Exception { Map map = new HashMap(); diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 6a1fc35c80b..69bb486207c 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -218,6 +218,8 @@ content into your application; rather pick only the properties that you need. server.tomcat.protocol-header-https-value=https # Value of the protocol header that indicates that the incoming request uses SSL. server.tomcat.remote-ip-header= # Name of the http header from which the remote ip is extracted. For instance `X-FORWARDED-FOR` server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. + server.jetty.acceptors= # Number of acceptor threads to use. + server.jetty.selectors= # Number of selector threads to use. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Enable access log. server.undertow.accesslog.pattern=common # Format pattern for access logs. diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java index 98f68ff0ff5..65a52568d5c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java @@ -91,6 +91,7 @@ import org.springframework.util.StringUtils; * @author Andrey Hihlovskiy * @author Andy Wilkinson * @author Eddú Meléndez + * @author Venil Noronha * @see #setPort(int) * @see #setConfigurations(Collection) * @see JettyEmbeddedServletContainer @@ -108,6 +109,16 @@ public class JettyEmbeddedServletContainerFactory private boolean useForwardHeaders; + /** + * The number of acceptor threads to use. + */ + private int acceptors = -1; + + /** + * The number of selector threads to use. + */ + private int selectors = -1; + private List jettyServerCustomizers = new ArrayList(); private ResourceLoader resourceLoader; @@ -143,7 +154,7 @@ public class JettyEmbeddedServletContainerFactory ServletContextInitializer... initializers) { JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext(); int port = (getPort() >= 0 ? getPort() : 0); - Server server = new Server(new InetSocketAddress(getAddress(), port)); + Server server = createServer(port); configureWebAppContext(context, initializers); server.setHandler(addHandlerWrappers(context)); this.logger.info("Server initialized with port: " + port); @@ -163,6 +174,21 @@ public class JettyEmbeddedServletContainerFactory return getJettyEmbeddedServletContainer(server); } + private Server createServer(int port) { + Server server = new Server(); + server.setConnectors(new Connector[] { createConnector(port, server) }); + return server; + } + + private ServerConnector createConnector(int port, Server server) { + ServerConnector connector = new ServerConnector(server, this.acceptors, + this.selectors); + InetSocketAddress address = new InetSocketAddress(getAddress(), port); + connector.setHost(address.getHostName()); + connector.setPort(address.getPort()); + return connector; + } + private Handler addHandlerWrappers(Handler handler) { if (getCompression() != null && getCompression().getEnabled()) { handler = applyWrapper(handler, createGzipHandler()); @@ -489,6 +515,24 @@ public class JettyEmbeddedServletContainerFactory this.useForwardHeaders = useForwardHeaders; } + /** + * Set the number of acceptor threads to use. + * @param acceptors the number of acceptor threads to use + * @since 1.4.0 + */ + public void setAcceptors(int acceptors) { + this.acceptors = acceptors; + } + + /** + * Set the number of selector threads to use. + * @param selectors the number of selector threads to use + * @since 1.4.0 + */ + public void setSelectors(int selectors) { + this.selectors = selectors; + } + /** * Sets {@link JettyServerCustomizer}s that will be applied to the {@link Server} * before it is started. Calling this method will replace any existing configurations.