From 068c3165b2e1d5c569b57a4dacf3fc5bb4d889d0 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 27 Jan 2026 11:54:26 +0100 Subject: [PATCH] Restore server.jetty.threads.max property for Jetty's virtual thread pool Closes gh-48982 --- .../autoconfigure/web/ServerProperties.java | 3 +-- ...verFactoryCustomizerAutoConfiguration.java | 13 +++++++---- ...tualThreadsWebServerFactoryCustomizer.java | 22 ++++++++++++++----- ...hreadsWebServerFactoryCustomizerTests.java | 7 +++++- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index afd4ed46c8d..d72b2b4a239 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -1434,8 +1434,7 @@ public class ServerProperties { private Integer selectors = -1; /** - * Maximum number of threads. Doesn't have an effect if virtual threads are - * enabled. + * Maximum number of threads. */ private Integer max = 200; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java index 6ea7d99bf43..19449a75488 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java @@ -83,16 +83,21 @@ public class EmbeddedWebServerFactoryCustomizerAutoConfiguration { @ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class }) public static class JettyWebServerFactoryCustomizerConfiguration { + private final ServerProperties serverProperties; + + JettyWebServerFactoryCustomizerConfiguration(ServerProperties serverProperties) { + this.serverProperties = serverProperties; + } + @Bean - public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, - ServerProperties serverProperties) { - return new JettyWebServerFactoryCustomizer(environment, serverProperties); + public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment) { + return new JettyWebServerFactoryCustomizer(environment, this.serverProperties); } @Bean @ConditionalOnThreading(Threading.VIRTUAL) JettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer() { - return new JettyVirtualThreadsWebServerFactoryCustomizer(); + return new JettyVirtualThreadsWebServerFactoryCustomizer(this.serverProperties); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizer.java index 740ae7113f1..914dbf3bac8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizer.java @@ -20,6 +20,7 @@ import org.eclipse.jetty.util.VirtualThreads; import org.eclipse.jetty.util.thread.VirtualThreadPool; import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.ServerProperties.Jetty.Threads; import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.Ordered; @@ -35,18 +36,24 @@ import org.springframework.util.Assert; public class JettyVirtualThreadsWebServerFactoryCustomizer implements WebServerFactoryCustomizer, Ordered { - public JettyVirtualThreadsWebServerFactoryCustomizer() { + private final ServerProperties serverProperties; + /** + * Create a new JettyVirtualThreadsWebServerFactoryCustomizer. + * @deprecated since 3.5.11 for removal in 4.2.0 in favor of + * {@link #JettyVirtualThreadsWebServerFactoryCustomizer(ServerProperties)} + */ + @Deprecated(since = "3.5.11", forRemoval = true) + public JettyVirtualThreadsWebServerFactoryCustomizer() { + this(null); } /** * Create a new JettyVirtualThreadsWebServerFactoryCustomizer. - * @param serverProperties server properties - * @deprecated since 3.4.12 for removal in 4.0.0 in favor of - * {@link JettyVirtualThreadsWebServerFactoryCustomizer}. + * @param serverProperties the server properties */ - @Deprecated(since = "3.4.12", forRemoval = true) public JettyVirtualThreadsWebServerFactoryCustomizer(ServerProperties serverProperties) { + this.serverProperties = serverProperties; } @Override @@ -54,6 +61,11 @@ public class JettyVirtualThreadsWebServerFactoryCustomizer Assert.state(VirtualThreads.areSupported(), "Virtual threads are not supported"); VirtualThreadPool virtualThreadPool = new VirtualThreadPool(); virtualThreadPool.setName("jetty-"); + if (this.serverProperties != null) { + Threads properties = this.serverProperties.getJetty().getThreads(); + int maxThreadCount = (properties.getMax() > 0) ? properties.getMax() : 200; + virtualThreadPool.setMaxThreads(maxThreadCount); + } factory.setThreadPool(virtualThreadPool); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizerTests.java index dff16454854..95c5c6a112b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyVirtualThreadsWebServerFactoryCustomizerTests.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; +import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory; import static org.assertj.core.api.Assertions.assertThat; @@ -38,13 +39,17 @@ class JettyVirtualThreadsWebServerFactoryCustomizerTests { @Test @EnabledForJreRange(min = JRE.JAVA_21) void shouldConfigureVirtualThreads() { - JettyVirtualThreadsWebServerFactoryCustomizer customizer = new JettyVirtualThreadsWebServerFactoryCustomizer(); + ServerProperties serverProperties = new ServerProperties(); + serverProperties.getJetty().getThreads().setMax(100); + JettyVirtualThreadsWebServerFactoryCustomizer customizer = new JettyVirtualThreadsWebServerFactoryCustomizer( + serverProperties); ConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class); customizer.customize(factory); then(factory).should().setThreadPool(assertArg((threadPool) -> { assertThat(threadPool).isInstanceOf(VirtualThreadPool.class); VirtualThreadPool virtualThreadPool = (VirtualThreadPool) threadPool; assertThat(virtualThreadPool.getName()).isEqualTo("jetty-"); + assertThat(virtualThreadPool.getMaxThreads()).isEqualTo(100); })); }