Browse Source

Enable virtual threads on Tomcat

Closes gh-35704
pull/35902/head
Moritz Halbritter 3 years ago
parent
commit
f81787e65d
  1. 4
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java
  2. 6
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/ServletManagementChildContextConfiguration.java
  3. 7
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java
  4. 47
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatVirtualThreadsWebServerFactoryCustomizer.java
  5. 4
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java
  6. 64
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatVirtualThreadsWebServerFactoryCustomizerTests.java

4
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java

@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.embedded.JettyWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.JettyWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.TomcatVirtualThreadsWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryCustomizer;
@ -76,7 +77,8 @@ public class ReactiveManagementChildContextConfiguration {
ReactiveManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) { ReactiveManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {
super(beanFactory, ReactiveWebServerFactoryCustomizer.class, TomcatWebServerFactoryCustomizer.class, super(beanFactory, ReactiveWebServerFactoryCustomizer.class, TomcatWebServerFactoryCustomizer.class,
TomcatReactiveWebServerFactoryCustomizer.class, JettyWebServerFactoryCustomizer.class, TomcatReactiveWebServerFactoryCustomizer.class,
TomcatVirtualThreadsWebServerFactoryCustomizer.class, JettyWebServerFactoryCustomizer.class,
UndertowWebServerFactoryCustomizer.class, NettyWebServerFactoryCustomizer.class); UndertowWebServerFactoryCustomizer.class, NettyWebServerFactoryCustomizer.class);
} }

6
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/ServletManagementChildContextConfiguration.java

@ -40,6 +40,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.embedded.JettyWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.JettyWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.TomcatVirtualThreadsWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryCustomizer;
@ -122,8 +123,9 @@ class ServletManagementChildContextConfiguration {
ServletManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) { ServletManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {
super(beanFactory, ServletWebServerFactoryCustomizer.class, TomcatServletWebServerFactoryCustomizer.class, super(beanFactory, ServletWebServerFactoryCustomizer.class, TomcatServletWebServerFactoryCustomizer.class,
TomcatWebServerFactoryCustomizer.class, JettyWebServerFactoryCustomizer.class, TomcatWebServerFactoryCustomizer.class, TomcatVirtualThreadsWebServerFactoryCustomizer.class,
UndertowServletWebServerFactoryCustomizer.class, UndertowWebServerFactoryCustomizer.class); JettyWebServerFactoryCustomizer.class, UndertowServletWebServerFactoryCustomizer.class,
UndertowWebServerFactoryCustomizer.class);
} }
@Override @Override

7
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java

@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment; import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnVirtualThreads;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -62,6 +63,12 @@ public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties); return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
} }
@Bean
@ConditionalOnVirtualThreads
TomcatVirtualThreadsWebServerFactoryCustomizer tomcatVirtualThreadsProtocolHandlerCustomizer() {
return new TomcatVirtualThreadsWebServerFactoryCustomizer();
}
} }
/** /**

47
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatVirtualThreadsWebServerFactoryCustomizer.java

@ -0,0 +1,47 @@
/*
* Copyright 2012-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
import org.apache.coyote.ProtocolHandler;
import org.apache.tomcat.util.threads.VirtualThreadExecutor;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.core.Ordered;
/**
* Activates {@link VirtualThreadExecutor} on {@link ProtocolHandler Tomcat's protocol
* handler}.
*
* @author Moritz Halbritter
* @since 3.2.0
*/
public class TomcatVirtualThreadsWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
factory.addProtocolHandlerCustomizers(
(protocolHandler) -> protocolHandler.setExecutor(new VirtualThreadExecutor("tomcat-handler-")));
}
@Override
public int getOrder() {
return TomcatWebServerFactoryCustomizer.order + 1;
}
}

4
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java

@ -67,6 +67,8 @@ import org.springframework.util.unit.DataSize;
public class TomcatWebServerFactoryCustomizer public class TomcatWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered { implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
static final int order = 0;
private final Environment environment; private final Environment environment;
private final ServerProperties serverProperties; private final ServerProperties serverProperties;
@ -78,7 +80,7 @@ public class TomcatWebServerFactoryCustomizer
@Override @Override
public int getOrder() { public int getOrder() {
return 0; return order;
} }
@Override @Override

64
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatVirtualThreadsWebServerFactoryCustomizerTests.java

@ -0,0 +1,64 @@
/*
* Copyright 2012-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
import java.util.function.Consumer;
import org.apache.tomcat.util.threads.VirtualThreadExecutor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TomcatVirtualThreadsWebServerFactoryCustomizer}.
*
* @author Moritz Halbritter
*/
class TomcatVirtualThreadsWebServerFactoryCustomizerTests {
private final TomcatVirtualThreadsWebServerFactoryCustomizer customizer = new TomcatVirtualThreadsWebServerFactoryCustomizer();
@Test
@EnabledForJreRange(min = JRE.JAVA_21)
void shouldSetVirtualThreadExecutor() {
withWebServer((webServer) -> assertThat(webServer.getTomcat().getConnector().getProtocolHandler().getExecutor())
.isInstanceOf(VirtualThreadExecutor.class));
}
private TomcatWebServer getWebServer() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);
this.customizer.customize(factory);
return (TomcatWebServer) factory.getWebServer();
}
private void withWebServer(Consumer<TomcatWebServer> callback) {
TomcatWebServer webServer = getWebServer();
webServer.start();
try {
callback.accept(webServer);
}
finally {
webServer.stop();
}
}
}
Loading…
Cancel
Save