Repackage web server classes

Issue: 44286
Issue: 44067
This commit is contained in:
Andy Wilkinson
2025-02-06 11:01:05 +00:00
committed by Phillip Webb
parent 778f58c9e1
commit 96785b6980
405 changed files with 5793 additions and 5178 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -28,8 +28,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
@@ -82,7 +82,7 @@ class PulsarAutoConfigurationIntegrationTests {
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ DispatcherServletAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class,
@ImportAutoConfiguration({ DispatcherServletAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
PulsarAutoConfiguration.class, PulsarReactiveAutoConfiguration.class })
@Import(TestWebController.class)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -27,8 +27,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.annotation.ImportCandidates;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

View File

@@ -56,8 +56,8 @@ import org.springframework.util.unit.DataSize;
* {@link EnableAutoConfiguration Auto-configuration} for RSocket servers. In the case of
* {@link org.springframework.boot.WebApplicationType#REACTIVE}, the RSocket server is
* added as a WebSocket endpoint on the existing
* {@link org.springframework.boot.web.embedded.netty.NettyWebServer}. If a specific
* server port is configured, a new standalone RSocket server is created.
* {@link org.springframework.boot.web.server.reactive.netty.NettyWebServer}. If a
* specific server port is configured, a new standalone RSocket server is created.
*
* @author Brian Clozel
* @author Scott Frederick

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -29,7 +29,7 @@ import reactor.netty.http.server.WebsocketServerSpec;
import reactor.netty.http.server.WebsocketServerSpec.Builder;
import org.springframework.boot.rsocket.server.RSocketServerCustomizer;
import org.springframework.boot.web.embedded.netty.NettyRouteProvider;
import org.springframework.boot.web.server.reactive.netty.NettyRouteProvider;
/**
* {@link NettyRouteProvider} that configures an RSocket Websocket endpoint.

View File

@@ -41,8 +41,8 @@ import org.springframework.boot.web.server.Http2;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.servlet.server.Jsp;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.boot.web.server.servlet.Jsp;
import org.springframework.boot.web.server.servlet.Session;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataSize;

View File

@@ -1,136 +0,0 @@
/*
* Copyright 2012-2024 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 io.undertow.Undertow;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader;
import org.xnio.SslClientAuthMode;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.task.VirtualThreadTaskExecutor;
/**
* {@link EnableAutoConfiguration Auto-configuration} for embedded servlet and reactive
* web servers customizations.
*
* @author Phillip Webb
* @author Moritz Halbritter
* @since 2.0.0
*/
@AutoConfiguration
@ConditionalOnNotWarDeployment
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
/**
* Nested configuration if Tomcat is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration {
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
TomcatVirtualThreadsWebServerFactoryCustomizer tomcatVirtualThreadsProtocolHandlerCustomizer() {
return new TomcatVirtualThreadsWebServerFactoryCustomizer();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
public static class JettyWebServerFactoryCustomizerConfiguration {
@Bean
public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
JettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new JettyVirtualThreadsWebServerFactoryCustomizer(serverProperties);
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
public static class UndertowWebServerFactoryCustomizerConfiguration {
@Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
UndertowDeploymentInfoCustomizer virtualThreadsUndertowDeploymentInfoCustomizer() {
return (deploymentInfo) -> deploymentInfo.setExecutor(new VirtualThreadTaskExecutor("undertow-"));
}
}
/**
* Nested configuration if Netty is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpServer.class)
public static class NettyWebServerFactoryCustomizerConfiguration {
@Bean
public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new NettyWebServerFactoryCustomizer(environment, serverProperties);
}
}
}

View File

@@ -1,123 +0,0 @@
/*
* 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.reactive;
import io.undertow.Undertow;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import reactor.netty.http.server.HttpServer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigurations;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.netty.NettyRouteProvider;
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.client.ReactorResourceFactory;
/**
* Configuration classes for reactive web servers
* <p>
* Those should be {@code @Import} in a regular auto-configuration class to guarantee
* their order of execution.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Sergey Serdyuk
*/
abstract class ReactiveWebServerFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
@ConditionalOnClass({ HttpServer.class })
@Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class)
static class EmbeddedNetty {
@Bean
NettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory,
ObjectProvider<NettyRouteProvider> routes, ObjectProvider<NettyServerCustomizer> serverCustomizers) {
NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();
serverFactory.setResourceFactory(resourceFactory);
routes.orderedStream().forEach(serverFactory::addRouteProviders);
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return serverFactory;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
@ConditionalOnClass({ org.apache.catalina.startup.Tomcat.class })
static class EmbeddedTomcat {
@Bean
TomcatReactiveWebServerFactory tomcatReactiveWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());
factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().toList());
factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());
return factory;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
@ConditionalOnClass({ org.eclipse.jetty.server.Server.class, ServletHolder.class })
static class EmbeddedJetty {
@Bean
JettyReactiveWebServerFactory jettyReactiveWebServerFactory(
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return serverFactory;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
@ConditionalOnClass({ Undertow.class })
static class EmbeddedUndertow {
@Bean
UndertowReactiveWebServerFactory undertowReactiveWebServerFactory(
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
UndertowReactiveWebServerFactory factory = new UndertowReactiveWebServerFactory();
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList());
return factory;
}
}
}

View File

@@ -106,9 +106,8 @@ import org.springframework.web.server.session.WebSessionManager;
* @author Weix Sun
* @since 2.0.0
*/
@AutoConfiguration(after = { ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
ReactiveMultipartAutoConfiguration.class, ValidationAutoConfiguration.class,
WebSessionIdResolverAutoConfiguration.class })
@AutoConfiguration(after = { CodecsAutoConfiguration.class, ReactiveMultipartAutoConfiguration.class,
ValidationAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.jetty;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.jetty;
import org.eclipse.jetty.util.VirtualThreads;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
@@ -29,7 +29,7 @@ import org.springframework.util.Assert;
* Activates virtual threads on the {@link ConfigurableJettyWebServerFactory}.
*
* @author Moritz Halbritter
* @since 3.2.0
* @since 4.0.0
*/
public class JettyVirtualThreadsWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered {

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2012-2025 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.server.jetty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.reactive.jetty.JettyReactiveWebServerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.jetty.JettyServletWebServerAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* {@link Configuration Configuration} for a Jetty-based reactive or servlet web server.
*
* @author Andy Wilkinson
* @since 4.0.0
* @see JettyReactiveWebServerAutoConfiguration
* @see JettyServletWebServerAutoConfiguration
*/
@ConditionalOnNotWarDeployment
@Configuration(proxyBeanMethods = false)
public class JettyWebServerConfiguration {
@Bean
JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
JettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new JettyVirtualThreadsWebServerFactoryCustomizer(serverProperties);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.jetty;
import java.time.Duration;
import java.util.Arrays;
@@ -36,8 +36,8 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties.Jetty.Accesslog.Format;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
@@ -52,7 +52,7 @@ import org.springframework.util.unit.DataSize;
* @author Rafiullah Hamedy
* @author Florian Storz
* @author Michael Weidmann
* @since 2.0.0
* @since 4.0.0
*/
public class JettyWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered {

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet or reactive web server using
* Jetty.
*/
package org.springframework.boot.autoconfigure.web.server.jetty;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
package org.springframework.boot.autoconfigure.web.server.reactive;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@@ -23,44 +23,31 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.adapter.ForwardedHeaderTransformer;
/**
* {@link EnableAutoConfiguration Auto-configuration} for a reactive web server.
* {@link Configuration Configuration} for a reactive web server.
*
* @author Brian Clozel
* @author Scott Frederick
* @since 2.0.0
* @since 4.0.0
*/
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfiguration
@ConditionalOnClass(ReactiveHttpInputMessage.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ReactiveWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ReactiveWebServerFactoryConfiguration.EmbeddedTomcat.class,
ReactiveWebServerFactoryConfiguration.EmbeddedJetty.class,
ReactiveWebServerFactoryConfiguration.EmbeddedUndertow.class,
ReactiveWebServerFactoryConfiguration.EmbeddedNetty.class })
public class ReactiveWebServerFactoryAutoConfiguration {
@Import(ReactiveWebServerConfiguration.BeanPostProcessorsRegistrar.class)
public class ReactiveWebServerConfiguration {
@Bean
public ReactiveWebServerFactoryCustomizer reactiveWebServerFactoryCustomizer(ServerProperties serverProperties,
@@ -68,13 +55,6 @@ public class ReactiveWebServerFactoryAutoConfiguration {
return new ReactiveWebServerFactoryCustomizer(serverProperties, sslBundles.getIfAvailable());
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatReactiveWebServerFactoryCustomizer tomcatReactiveWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatReactiveWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "server.forward-headers-strategy", havingValue = "framework")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
package org.springframework.boot.autoconfigure.web.server.reactive;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;
import org.springframework.core.Ordered;
/**
@@ -30,7 +30,7 @@ import org.springframework.core.Ordered;
* @author Brian Clozel
* @author Yunkun Huang
* @author Scott Frederick
* @since 2.0.0
* @since 4.0.0
*/
public class ReactiveWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory>, Ordered {
@@ -51,7 +51,7 @@ public class ReactiveWebServerFactoryCustomizer
* Create a new {@link ReactiveWebServerFactoryCustomizer} instance.
* @param serverProperties the server properties
* @param sslBundles the SSL bundles
* @since 3.1.0
* @since 4.0.0
*/
public ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties, SslBundles sslBundles) {
this.serverProperties = serverProperties;

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2012-2025 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.server.reactive.jetty;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.server.Server;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.server.jetty.JettyWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.reactive.ReactiveWebServerConfiguration;
import org.springframework.boot.web.server.jetty.JettyServerCustomizer;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.jetty.JettyReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.ReactiveHttpInputMessage;
/**
* {@link EnableAutoConfiguration Auto-configuration} for a Jetty-based reactive web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ Server.class, ServletHolder.class, ReactiveHttpInputMessage.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Import({ JettyWebServerConfiguration.class, ReactiveWebServerConfiguration.class })
public class JettyReactiveWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
JettyReactiveWebServerFactory jettyReactiveWebServerFactory(
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return serverFactory;
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JakartaWebSocketServletContainerInitializer.class)
static class JettyWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketReactiveWebServerCustomizer")
WebSocketJettyReactiveWebServerFactoryCustomizer websocketServletWebServerCustomizer() {
return new WebSocketJettyReactiveWebServerFactoryCustomizer();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.websocket.reactive;
package org.springframework.boot.autoconfigure.web.server.reactive.jetty;
import jakarta.servlet.ServletContext;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
@@ -25,17 +25,17 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.jetty.JettyReactiveWebServerFactory;
import org.springframework.core.Ordered;
/**
* WebSocket customizer for {@link JettyReactiveWebServerFactory}.
*
* @author Andy Wilkinson
* @since 3.0.8
* @since 4.0.0
*/
public class JettyWebSocketReactiveWebServerCustomizer
public class WebSocketJettyReactiveWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<JettyReactiveWebServerFactory>, Ordered {
@Override

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a reactive web server using Jetty.
*/
package org.springframework.boot.autoconfigure.web.server.reactive.jetty;

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2012-2025 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.server.reactive.netty;
import reactor.netty.http.server.HttpServer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigurations.ReactorResourceFactoryConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.reactive.ReactiveWebServerConfiguration;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.netty.NettyRouteProvider;
import org.springframework.boot.web.server.reactive.netty.NettyServerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.client.ReactorResourceFactory;
/**
* {@link EnableAutoConfiguration Auto-configuration} for a Netty-based reactive web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ReactiveHttpInputMessage.class, HttpServer.class })
@Import({ ReactiveWebServerConfiguration.class, ReactorResourceFactoryConfiguration.class })
public class NettyReactiveWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
NettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory,
ObjectProvider<NettyRouteProvider> routes, ObjectProvider<NettyServerCustomizer> serverCustomizers) {
NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();
serverFactory.setResourceFactory(resourceFactory);
routes.orderedStream().forEach(serverFactory::addRouteProviders);
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return serverFactory;
}
@Bean
NettyReactiveWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new NettyReactiveWebServerFactoryCustomizer(environment, serverProperties);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.reactive.netty;
import java.time.Duration;
@@ -23,8 +23,8 @@ import io.netty.channel.ChannelOption;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
@@ -34,16 +34,16 @@ import org.springframework.core.env.Environment;
* @author Brian Clozel
* @author Chentao Qu
* @author Artsiom Yudovin
* @since 2.1.0
* @since 4.0.0
*/
public class NettyWebServerFactoryCustomizer
public class NettyReactiveWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory>, Ordered {
private final Environment environment;
private final ServerProperties serverProperties;
public NettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
public NettyReactiveWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
this.environment = environment;
this.serverProperties = serverProperties;
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a reactive web server using Netty.
*/
package org.springframework.boot.autoconfigure.web.server.reactive.netty;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2025 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.
@@ -15,6 +15,6 @@
*/
/**
* Configuration for embedded reactive and servlet web servers.
* Classes related to the auto-configuration of a reactive web server.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.reactive;

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2012-2025 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.server.reactive.tomcat;
import org.apache.catalina.startup.Tomcat;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.reactive.ReactiveWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.tomcat.TomcatWebServerConfiguration;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.server.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.ReactiveHttpInputMessage;
/**
* {@link EnableAutoConfiguration Auto-configuration} for a Tomcat-based reactive web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ReactiveHttpInputMessage.class, Tomcat.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Import({ TomcatWebServerConfiguration.class, ReactiveWebServerConfiguration.class })
public class TomcatReactiveWebServerAutoConfiguration {
@Bean
TomcatReactiveWebServerFactoryCustomizer tomcatReactiveWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatReactiveWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
TomcatReactiveWebServerFactory tomcatReactiveWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
factory.getConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());
factory.getContextCustomizers().addAll(contextCustomizers.orderedStream().toList());
factory.getProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());
return factory;
}
}

View File

@@ -14,15 +14,15 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
package org.springframework.boot.autoconfigure.web.server.reactive.tomcat;
import org.apache.catalina.core.AprLifecycleListener;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.UseApr;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.util.Assert;
/**
@@ -30,7 +30,7 @@ import org.springframework.util.Assert;
* web servers.
*
* @author Andy Wilkinson
* @since 2.2.0
* @since 4.0.0
*/
public class TomcatReactiveWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> {

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a reactive web server using Tomcat.
*/
package org.springframework.boot.autoconfigure.web.server.reactive.tomcat;

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2012-2025 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.server.reactive.undertow;
import io.undertow.Undertow;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.server.reactive.ReactiveWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.undertow.UndertowWebServerConfiguration;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.server.undertow.UndertowBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.ReactiveHttpInputMessage;
/**
* {@link EnableAutoConfiguration Auto-configuration} for an Undertow-based reactive web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ReactiveHttpInputMessage.class, Undertow.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Import({ UndertowWebServerConfiguration.class, ReactiveWebServerConfiguration.class })
public class UndertowReactiveWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
UndertowReactiveWebServerFactory undertowReactiveWebServerFactory(
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
UndertowReactiveWebServerFactory factory = new UndertowReactiveWebServerFactory();
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList());
return factory;
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a reactive web server using Undertow.
*/
package org.springframework.boot.autoconfigure.web.server.reactive.undertow;

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2012-2025 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.server.servlet;
import org.springframework.web.filter.ForwardedHeaderFilter;
/**
* Customizer for the auto-configured {@link ForwardedHeaderFilter}.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
public interface ForwardedHeaderFilterCustomizer {
/**
* Customizes the given {@code filter}.
* @param filter the filter to customize
*/
void customize(ForwardedHeaderFilter filter);
}

View File

@@ -14,10 +14,9 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@@ -26,22 +25,16 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.ConditionalOnMissingFilterBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.server.ErrorPageRegistrarBeanPostProcessor;
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
import org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.WebListenerRegistrar;
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -52,7 +45,7 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.ForwardedHeaderFilter;
/**
* {@link EnableAutoConfiguration Auto-configuration} for servlet web servers.
* {@link Configuration Configuration} for a servlet web server.
*
* @author Phillip Webb
* @author Dave Syer
@@ -60,21 +53,15 @@ import org.springframework.web.filter.ForwardedHeaderFilter;
* @author Brian Clozel
* @author Stephane Nicoll
* @author Scott Frederick
* @since 2.0.0
* @since 4.0.0
*/
@AutoConfiguration(after = SslAutoConfiguration.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Import(ServletWebServerConfiguration.BeanPostProcessorsRegistrar.class)
public class ServletWebServerConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
ObjectProvider<WebListenerRegistrar> webListenerRegistrars,
ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers, ObjectProvider<SslBundles> sslBundles) {
return new ServletWebServerFactoryCustomizer(serverProperties, webListenerRegistrars.orderedStream().toList(),
@@ -82,47 +69,23 @@ public class ServletWebServerFactoryAutoConfiguration {
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "server.forward-headers-strategy", havingValue = "framework")
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
static class ForwardedHeaderFilterConfiguration {
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
}
@Bean
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
customizerProvider.ifAvailable((customizer) -> customizer.customize(filter));
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
}
interface ForwardedHeaderFilterCustomizer {
void customize(ForwardedHeaderFilter filter);
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
customizerProvider.ifAvailable((customizer) -> customizer.customize(filter));
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
/**
* Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
* {@link ImportBeanDefinitionRegistrar} for early registration.
*/
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet;
import java.util.Collections;
import java.util.List;
@@ -23,9 +23,9 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;
import org.springframework.boot.web.servlet.WebListenerRegistrar;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.core.Ordered;
import org.springframework.util.CollectionUtils;
@@ -39,7 +39,7 @@ import org.springframework.util.CollectionUtils;
* @author Yunkun Huang
* @author Scott Frederick
* @author Lasse Wulff
* @since 2.0.0
* @since 4.0.0
*/
public class ServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
@@ -53,15 +53,10 @@ public class ServletWebServerFactoryCustomizer
private final SslBundles sslBundles;
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
this(serverProperties, Collections.emptyList());
this(serverProperties, Collections.emptyList(), Collections.emptyList(), null);
}
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties,
List<WebListenerRegistrar> webListenerRegistrars) {
this(serverProperties, webListenerRegistrars, null, null);
}
ServletWebServerFactoryCustomizer(ServerProperties serverProperties,
List<WebListenerRegistrar> webListenerRegistrars, List<CookieSameSiteSupplier> cookieSameSiteSuppliers,
SslBundles sslBundles) {
this.serverProperties = serverProperties;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,69 +14,59 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.websocket.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet.jetty;
import java.util.EnumSet;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterRegistration.Dynamic;
import jakarta.servlet.Servlet;
import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.websocket.server.WsSci;
import jakarta.servlet.ServletRequest;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.server.jetty.JettyWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.ServletWebServerConfiguration;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.jetty.JettyServerCustomizer;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
* Auto configuration for WebSocket servlet server in embedded Tomcat, Jetty or Undertow.
* Requires the appropriate WebSocket modules to be on the classpath.
* <p>
* If Tomcat's WebSocket support is detected on the classpath we add a customizer that
* installs the Tomcat WebSocket initializer. In a non-embedded server it should already
* be there.
* <p>
* If Jetty's WebSocket support is detected on the classpath we add a configuration that
* configures the context with WebSocket support. In a non-embedded server it should
* already be there.
* <p>
* If Undertow's WebSocket support is detected on the classpath we add a customizer that
* installs the Undertow WebSocket DeploymentInfo Customizer. In a non-embedded server it
* should already be there.
* {@link EnableAutoConfiguration Auto-configuration} for a Jetty-based servlet web
* server.
*
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.0.0
* @since 4.0.0
*/
@AutoConfiguration(before = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnClass({ Servlet.class, ServerContainer.class })
@AutoConfiguration
@ConditionalOnClass({ ServletRequest.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
public class WebSocketServletAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Tomcat.class, WsSci.class })
static class TomcatWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer")
TomcatWebSocketServletWebServerCustomizer websocketServletWebServerCustomizer() {
return new TomcatWebSocketServletWebServerCustomizer();
}
@Import({ JettyWebServerConfiguration.class, ServletWebServerConfiguration.class })
public class JettyServletWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
JettyServletWebServerFactory jettyServletWebServerFactory(ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return factory;
}
@Configuration(proxyBeanMethods = false)
@@ -85,8 +75,8 @@ public class WebSocketServletAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer")
JettyWebSocketServletWebServerCustomizer websocketServletWebServerCustomizer() {
return new JettyWebSocketServletWebServerCustomizer();
WebSocketJettyServletWebServerFactoryCustomizer websocketServletWebServerCustomizer() {
return new WebSocketJettyServletWebServerFactoryCustomizer();
}
@Bean
@@ -106,16 +96,4 @@ public class WebSocketServletAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(io.undertow.websockets.jsr.Bootstrap.class)
static class UndertowWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer")
UndertowWebSocketServletWebServerCustomizer websocketServletWebServerCustomizer() {
return new UndertowWebSocketServletWebServerCustomizer();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.websocket.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet.jetty;
import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
@@ -24,8 +24,8 @@ import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.core.Ordered;
/**
@@ -34,9 +34,9 @@ import org.springframework.core.Ordered;
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
* @since 2.0.0
* @since 4.0.0
*/
public class JettyWebSocketServletWebServerCustomizer
public class WebSocketJettyServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<JettyServletWebServerFactory>, Ordered {
@Override

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet web server using Jetty.
*/
package org.springframework.boot.autoconfigure.web.server.servlet.jetty;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2025 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.
@@ -15,6 +15,6 @@
*/
/**
* Auto-configuration for WebSocket support in reactive web servers.
* Classes related to the auto-configuration of a servlet web server.
*/
package org.springframework.boot.autoconfigure.websocket.reactive;
package org.springframework.boot.autoconfigure.web.server.servlet;

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2012-2025 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.server.servlet.tomcat;
import jakarta.servlet.ServletRequest;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.servlet.ForwardedHeaderFilterCustomizer;
import org.springframework.boot.autoconfigure.web.server.servlet.ServletWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.tomcat.TomcatWebServerConfiguration;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for a Tomcat-based servlet web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ServletRequest.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@Import({ ServletWebServerConfiguration.class, TomcatWebServerConfiguration.class })
public class TomcatServletWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.getConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());
factory.getContextCustomizers().addAll(contextCustomizers.orderedStream().toList());
factory.getProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());
return factory;
}
@Bean
TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnProperty(name = "server.forward-headers-strategy", havingValue = "framework")
ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
}
}

View File

@@ -14,17 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
import org.apache.catalina.core.AprLifecycleListener;
package org.springframework.boot.autoconfigure.web.server.servlet.tomcat;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.UseApr;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
@@ -33,14 +29,13 @@ import org.springframework.util.ObjectUtils;
*
* @author Brian Clozel
* @author Phillip Webb
* @since 2.0.0
*/
public class TomcatServletWebServerFactoryCustomizer
class TomcatServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {
private final ServerProperties serverProperties;
public TomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
TomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}
@@ -60,7 +55,6 @@ public class TomcatServletWebServerFactoryCustomizer
}
customizeUseRelativeRedirects(factory, tomcatProperties.isUseRelativeRedirects());
factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled());
factory.setUseApr(getUseApr(tomcatProperties.getUseApr()));
}
private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory, boolean redirectContextRoot) {
@@ -72,22 +66,4 @@ public class TomcatServletWebServerFactoryCustomizer
factory.addContextCustomizers((context) -> context.setUseRelativeRedirects(useRelativeRedirects));
}
private boolean getUseApr(UseApr useApr) {
return switch (useApr) {
case ALWAYS -> {
Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available");
yield true;
}
case WHEN_AVAILABLE -> isAprAvailable();
case NEVER -> false;
};
}
private boolean isAprAvailable() {
// At least one instance of AprLifecycleListener has to be created for
// isAprAvailable() to work
new AprLifecycleListener();
return AprLifecycleListener.isAprAvailable();
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet web server using Tomcat.
*/
package org.springframework.boot.autoconfigure.web.server.servlet.tomcat;

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2012-2025 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.server.servlet.undertow;
import io.undertow.Undertow;
import io.undertow.websockets.jsr.Bootstrap;
import jakarta.servlet.ServletRequest;
import org.xnio.SslClientAuthMode;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.servlet.ServletWebServerConfiguration;
import org.springframework.boot.autoconfigure.web.server.undertow.UndertowWebServerConfiguration;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.server.servlet.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.undertow.UndertowBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for an Undertow-based servlet web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ServletRequest.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@Import({ UndertowWebServerConfiguration.class, ServletWebServerConfiguration.class })
public class UndertowServletWebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
UndertowServletWebServerFactory undertowServletWebServerFactory(
ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers.orderedStream().toList());
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList());
return factory;
}
@Bean
UndertowServletWebServerFactoryCustomizer undertowServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new UndertowServletWebServerFactoryCustomizer(serverProperties);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Bootstrap.class)
static class UndertowWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer")
WebSocketUndertowServletWebServerFactoryCustomizer websocketServletWebServerCustomizer() {
return new WebSocketUndertowServletWebServerFactoryCustomizer();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,25 +14,23 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet.undertow;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.undertow.UndertowServletWebServerFactory;
/**
* {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to Undertow
* Servlet web servers.
*
* @author Andy Wilkinson
* @since 2.1.7
*/
public class UndertowServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
class UndertowServletWebServerFactoryCustomizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
private final ServerProperties serverProperties;
public UndertowServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
UndertowServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.websocket.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet.undertow;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.server.servlet.undertow.UndertowServletWebServerFactory;
import org.springframework.core.Ordered;
/**
@@ -30,7 +30,7 @@ import org.springframework.core.Ordered;
* @author Phillip Webb
* @since 2.0.0
*/
public class UndertowWebSocketServletWebServerCustomizer
public class WebSocketUndertowServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<UndertowServletWebServerFactory>, Ordered {
@Override

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet web server using Undertow.
*/
package org.springframework.boot.autoconfigure.web.server.servlet.undertow;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.tomcat;
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.boot.web.server.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.core.Ordered;
/**
@@ -28,7 +28,7 @@ import org.springframework.core.Ordered;
* handler}.
*
* @author Moritz Halbritter
* @since 3.2.0
* @since 4.0.0
*/
public class TomcatVirtualThreadsWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2012-2025 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.server.tomcat;
import org.apache.tomcat.websocket.server.WsSci;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.server.reactive.tomcat.TomcatReactiveWebServerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* {@link Configuration Configuration} for a Tomcat-based reactive or servlet web server.
*
* @author Andy Wilkinson
* @since 4.0.0
* @see TomcatReactiveWebServerAutoConfiguration
* @see TomcatServletWebServerAutoConfiguration
*/
@ConditionalOnNotWarDeployment
@Configuration(proxyBeanMethods = false)
public class TomcatWebServerConfiguration {
@Bean
TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
TomcatVirtualThreadsWebServerFactoryCustomizer tomcatVirtualThreadsProtocolHandlerCustomizer() {
return new TomcatVirtualThreadsWebServerFactoryCustomizer();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WsSci.class)
static class TomcatWebSocketConfiguration {
@Bean
WebSocketTomcatWebServerFactoryCustomizer webSocketWebServerCustomizer() {
return new WebSocketTomcatWebServerFactoryCustomizer();
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.tomcat;
import java.time.Duration;
import java.util.List;
@@ -22,6 +22,7 @@ import java.util.function.ObjIntConsumer;
import java.util.stream.Collectors;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.ErrorReportValve;
import org.apache.catalina.valves.RemoteIpValve;
@@ -36,18 +37,19 @@ import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeAttribu
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.UseApr;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataSize;
/**
* Customization for Tomcat-specific features common for both Servlet and Reactive
* servers.
* Customization for Tomcat-specific features common to both Servlet and Reactive servers.
*
* @author Brian Clozel
* @author Yulin Qin
@@ -62,7 +64,7 @@ import org.springframework.util.unit.DataSize;
* @author Parviz Rozikov
* @author Florian Storz
* @author Michael Weidmann
* @since 2.0.0
* @since 4.0.0
*/
public class TomcatWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
@@ -149,6 +151,25 @@ public class TomcatWebServerFactoryCustomizer
.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));
customizeStaticResources(factory);
customizeErrorReportValve(this.serverProperties.getError(), factory);
factory.setUseApr(getUseApr(this.serverProperties.getTomcat().getUseApr()));
}
private boolean getUseApr(UseApr useApr) {
return switch (useApr) {
case ALWAYS -> {
Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available");
yield true;
}
case WHEN_AVAILABLE -> isAprAvailable();
case NEVER -> false;
};
}
private boolean isAprAvailable() {
// At least one instance of AprLifecycleListener has to be created for
// isAprAvailable() to work
new AprLifecycleListener();
return AprLifecycleListener.isAprAvailable();
}
private boolean isPositive(int value) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,33 +14,25 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.websocket.servlet;
package org.springframework.boot.autoconfigure.web.server.tomcat;
import org.apache.tomcat.websocket.server.WsSci;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.core.Ordered;
import org.springframework.boot.web.server.tomcat.ConfigurableTomcatWebServerFactory;
/**
* WebSocket customizer for {@link TomcatServletWebServerFactory}.
* {@link WebServerFactoryCustomizer} that configures Tomcat's WebSocket support.
*
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
* @since 2.0.0
* @since 4.0.0
*/
public class TomcatWebSocketServletWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {
public class WebSocketTomcatWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
public void customize(ConfigurableTomcatWebServerFactory factory) {
factory.addContextCustomizers((context) -> context.addServletContainerInitializer(new WsSci(), null));
}
@Override
public int getOrder() {
return 0;
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet or reactive web server using
* Tomcat.
*/
package org.springframework.boot.autoconfigure.web.server.tomcat;

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2012-2025 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.server.undertow;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.server.servlet.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.task.VirtualThreadTaskExecutor;
/**
* {@link Configuration Configuration} for an Undertow-based reactive or servlet web
* server.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
@ConditionalOnNotWarDeployment
@Configuration(proxyBeanMethods = false)
public class UndertowWebServerConfiguration {
@Bean
UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
UndertowDeploymentInfoCustomizer virtualThreadsUndertowDeploymentInfoCustomizer() {
return (deploymentInfo) -> deploymentInfo.setExecutor(new VirtualThreadTaskExecutor("undertow-"));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.undertow;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
@@ -34,8 +34,8 @@ import org.springframework.boot.autoconfigure.web.ServerProperties.Undertow;
import org.springframework.boot.autoconfigure.web.ServerProperties.Undertow.Accesslog;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.undertow.ConfigurableUndertowWebServerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
@@ -54,7 +54,7 @@ import org.springframework.util.unit.DataSize;
* @author Arstiom Yudovin
* @author Rafiullah Hamedy
* @author HaiTao Zhang
* @since 2.0.0
* @since 4.0.0
*/
public class UndertowWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableUndertowWebServerFactory>, Ordered {

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Classes related to the auto-configuration of a servlet or reactive web server using
* Undertow.
*/
package org.springframework.boot.autoconfigure.web.server.undertow;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -63,7 +63,7 @@ import org.springframework.web.servlet.DispatcherServlet;
* @since 2.0.0
*/
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {

View File

@@ -1,126 +0,0 @@
/*
* 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.servlet;
import io.undertow.Undertow;
import jakarta.servlet.Servlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader;
import org.xnio.SslClientAuthMode;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration classes for servlet web servers
* <p>
* Those should be {@code @Import} in a regular auto-configuration class to guarantee
* their order of execution.
*
* @author Phillip Webb
* @author Dave Syer
* @author Ivan Sopov
* @author Brian Clozel
* @author Stephane Nicoll
* @author Raheela Asalm
* @author Sergey Serdyuk
*/
@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());
factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().toList());
factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());
return factory;
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
@Bean
JettyServletWebServerFactory jettyServletWebServerFactory(
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
return factory;
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
@Bean
UndertowServletWebServerFactory undertowServletWebServerFactory(
ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers.orderedStream().toList());
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList());
return factory;
}
@Bean
UndertowServletWebServerFactoryCustomizer undertowServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new UndertowServletWebServerFactoryCustomizer(serverProperties);
}
}
}

View File

@@ -26,8 +26,8 @@ import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -42,7 +42,7 @@ import org.springframework.web.servlet.ModelAndView;
* Basic global error {@link Controller @Controller}, rendering {@link ErrorAttributes}.
* More specific errors can be handled either using Spring MVC abstractions (e.g.
* {@code @ExceptionHandler}) or by adding servlet
* {@link AbstractServletWebServerFactory#setErrorPages server error pages}.
* {@link ConfigurableServletWebServerFactory#setErrorPages server error pages}.
*
* @author Dave Syer
* @author Phillip Webb

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -33,7 +33,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
@@ -59,7 +58,7 @@ import org.springframework.xml.xsd.SimpleXsdSchema;
* @author Stephane Nicoll
* @since 1.4.0
*/
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(MessageDispatcherServlet.class)
@ConditionalOnMissingBean(WsConfigurationSupport.class)

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2012-2020 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.websocket.reactive;
import org.apache.tomcat.websocket.server.WsSci;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.core.Ordered;
/**
* WebSocket customizer for {@link TomcatReactiveWebServerFactory}.
*
* @author Brian Clozel
* @since 2.0.0
*/
public class TomcatWebSocketReactiveWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatReactiveWebServerFactory>, Ordered {
@Override
public void customize(TomcatReactiveWebServerFactory factory) {
factory.addContextCustomizers((context) -> context.addServletContainerInitializer(new WsSci(), null));
}
@Override
public int getOrder() {
return 0;
}
}

View File

@@ -1,73 +0,0 @@
/*
* 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.websocket.reactive;
import jakarta.servlet.Servlet;
import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.websocket.server.WsSci;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto-configuration for WebSocket reactive server in Tomcat, Jetty or Undertow. Requires
* the appropriate WebSocket modules to be on the classpath.
* <p>
* If Tomcat's WebSocket support is detected on the classpath we add a customizer that
* installs the Tomcat WebSocket initializer.
*
* @author Brian Clozel
* @since 2.0.0
*/
@AutoConfiguration(before = ReactiveWebServerFactoryAutoConfiguration.class)
@ConditionalOnClass({ Servlet.class, ServerContainer.class })
@ConditionalOnWebApplication(type = Type.REACTIVE)
public class WebSocketReactiveAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Tomcat.class, WsSci.class })
static class TomcatWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketReactiveWebServerCustomizer")
TomcatWebSocketReactiveWebServerCustomizer websocketReactiveWebServerCustomizer() {
return new TomcatWebSocketReactiveWebServerCustomizer();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JakartaWebSocketServletContainerInitializer.class)
static class JettyWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name = "websocketReactiveWebServerCustomizer")
JettyWebSocketReactiveWebServerCustomizer websocketServletWebServerCustomizer() {
return new JettyWebSocketReactiveWebServerCustomizer();
}
}
}

View File

@@ -136,23 +136,26 @@ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.ReactiveMultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
org.springframework.boot.autoconfigure.web.server.reactive.jetty.JettyReactiveWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.reactive.netty.NettyReactiveWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.reactive.tomcat.TomcatReactiveWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.reactive.undertow.UndertowReactiveWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.servlet.jetty.JettyServletWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.server.servlet.undertow.UndertowServletWebServerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -31,8 +31,8 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
@@ -111,7 +111,7 @@ class SpringApplicationAdminJmxAutoConfigurationTests {
@Test
void registerWithSimpleWebApp() throws Exception {
try (ConfigurableApplicationContext context = new SpringApplicationBuilder()
.sources(ServletWebServerFactoryAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
.sources(TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
MultipleMBeanExportersConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class)
.run("--" + ENABLE_ADMIN_PROP, "--server.port=0")) {
assertThat(context).isInstanceOf(ServletWebServerApplicationContext.class);

View File

@@ -22,8 +22,8 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;

View File

@@ -22,8 +22,8 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

View File

@@ -38,9 +38,9 @@ import org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContex
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.netty.NettyRouteProvider;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.netty.NettyRouteProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.client.RSocketGraphQlClient;

View File

@@ -30,7 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindException;
import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@@ -185,7 +185,7 @@ class H2ConsoleAutoConfigurationTests {
void dataSourceIsNotInitializedEarly(CapturedOutput output) {
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(H2ConsoleAutoConfiguration.class,
ServletWebServerFactoryAutoConfiguration.class))
TomcatServletWebServerAutoConfiguration.class))
.withUserConfiguration(EarlyInitializationConfiguration.class)
.withPropertyValues("spring.h2.console.enabled=true", "server.port=0")
.run((context) -> {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -72,7 +72,7 @@ class JerseyAutoConfigurationCustomApplicationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
static class TestConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -91,7 +91,7 @@ class JerseyAutoConfigurationCustomFilterContextPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -90,7 +90,7 @@ class JerseyAutoConfigurationCustomFilterPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.ApplicationContext;
@@ -67,7 +67,7 @@ class JerseyAutoConfigurationCustomLoadOnStartupTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ JerseyAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -117,7 +117,7 @@ class JerseyAutoConfigurationCustomObjectMapperProviderTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JacksonAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -89,7 +89,7 @@ class JerseyAutoConfigurationCustomServletContextPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -89,7 +89,7 @@ class JerseyAutoConfigurationCustomServletPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -31,7 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -88,7 +88,7 @@ class JerseyAutoConfigurationDefaultFilterPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -31,7 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -87,7 +87,7 @@ class JerseyAutoConfigurationDefaultServletPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -33,7 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -127,7 +127,7 @@ class JerseyAutoConfigurationObjectMapperProviderTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JacksonAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -32,12 +32,12 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationServletContainerTests.Application;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -62,7 +62,7 @@ class JerseyAutoConfigurationServletContainerTests {
assertThat(output).contains("Servlet " + Application.class.getName() + " was not registered");
}
@ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@Import(ContainerConfiguration.class)
@Path("/hello")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -31,7 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -87,7 +87,7 @@ class JerseyAutoConfigurationWithoutApplicationPathTests {
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -26,8 +26,8 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.reactive.netty.NettyReactiveWebServerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.reactive.result.view.MustacheView;
@@ -81,7 +81,7 @@ class MustacheAutoConfigurationReactiveIntegrationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ ReactiveWebServerFactoryAutoConfiguration.class, WebFluxAutoConfiguration.class,
@Import({ NettyReactiveWebServerAutoConfiguration.class, WebFluxAutoConfiguration.class,
HttpHandlerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
@Controller
static class Application {

View File

@@ -33,8 +33,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -132,7 +132,7 @@ class MustacheAutoConfigurationServletIntegrationTests {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ ServletWebServerFactoryAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
@Import({ TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -29,10 +29,10 @@ import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfig
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -27,7 +27,7 @@ import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguratio
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -39,7 +39,7 @@ import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -23,7 +23,7 @@ import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplic
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext;
import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;

View File

@@ -21,7 +21,7 @@ import java.util.LinkedHashMap;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
@@ -52,7 +52,7 @@ class SessionAutoConfigurationEarlyInitializationIntegrationTests {
@Configuration(proxyBeanMethods = false)
@EnableSpringHttpSession
@ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, SessionAutoConfiguration.class })
@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, SessionAutoConfiguration.class })
static class TestConfiguration {
@Bean

View File

@@ -44,11 +44,11 @@ import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.server.MimeMappings.Mapping;
import org.springframework.boot.web.server.jetty.JettyWebServer;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.unit.DataSize;

View File

@@ -1,57 +0,0 @@
/*
* Copyright 2012-2024 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 io.undertow.servlet.api.DeploymentInfo;
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.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration.UndertowWebServerFactoryCustomizerConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.core.task.VirtualThreadTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link UndertowWebServerFactoryCustomizerConfiguration}.
*
* @author Moritz Halbritter
*/
class UndertowWebServerFactoryCustomizerConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
AnnotationConfigServletWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(EmbeddedWebServerFactoryCustomizerAutoConfiguration.class));
@EnabledForJreRange(min = JRE.JAVA_21)
@Test
void shouldUseVirtualThreadsIfEnabled() {
this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run((context) -> {
assertThat(context).hasSingleBean(UndertowDeploymentInfoCustomizer.class);
assertThat(context).hasBean("virtualThreadsUndertowDeploymentInfoCustomizer");
UndertowDeploymentInfoCustomizer customizer = context.getBean(UndertowDeploymentInfoCustomizer.class);
DeploymentInfo deploymentInfo = new DeploymentInfo();
customizer.customize(deploymentInfo);
assertThat(deploymentInfo.getExecutor()).isInstanceOf(VirtualThreadTaskExecutor.class);
});
}
}

View File

@@ -1,569 +0,0 @@
/*
* Copyright 2012-2025 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.reactive;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.eclipse.jetty.server.Server;
import org.junit.jupiter.api.Test;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.server.adapter.ForwardedHeaderTransformer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ReactiveWebServerFactoryAutoConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
@DirtiesUrlFactories
class ReactiveWebServerFactoryAutoConfigurationTests {
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(
AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class, SslAutoConfiguration.class));
@Test
void createFromConfigClass() {
this.contextRunner.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class)
.run((context) -> {
assertThat(context.getBeansOfType(ReactiveWebServerFactory.class)).hasSize(1);
assertThat(context.getBeansOfType(WebServerFactoryCustomizer.class)).hasSize(2);
assertThat(context.getBeansOfType(ReactiveWebServerFactoryCustomizer.class)).hasSize(1);
});
}
@Test
void missingHttpHandler() {
this.contextRunner.withUserConfiguration(MockWebServerConfiguration.class)
.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)
.rootCause()
.hasMessageContaining("missing HttpHandler bean"));
}
@Test
void multipleHttpHandler() {
this.contextRunner
.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,
TooManyHttpHandlers.class)
.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)
.rootCause()
.hasMessageContaining("multiple HttpHandler beans : httpHandler,additionalHttpHandler"));
}
@Test
void customizeReactiveWebServer() {
this.contextRunner
.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,
ReactiveWebServerCustomization.class)
.run((context) -> assertThat(context.getBean(MockReactiveWebServerFactory.class).getPort())
.isEqualTo(9000));
}
@Test
void defaultWebServerIsTomcat() {
// Tomcat should be chosen over Netty if the Tomcat library is present.
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.port=0")
.run((context) -> assertThat(context.getBean(ReactiveWebServerFactory.class))
.isInstanceOf(TomcatReactiveWebServerFactory.class));
}
@Test
void webServerFailsWithInvalidSslBundle() {
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.port=0", "server.ssl.bundle=test-bundle")
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure().getCause()).isInstanceOf(NoSuchSslBundleException.class)
.withFailMessage("test");
});
}
@Test
void tomcatConnectorCustomizerBeanIsAddedToFactory() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class, TomcatConnectorCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getTomcatConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatConnectorCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class,
DoubleRegistrationTomcatConnectorCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getTomcatConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatContextCustomizerBeanIsAddedToFactory() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class, TomcatContextCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer", TomcatContextCustomizer.class);
assertThat(factory.getTomcatContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatContextCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class,
DoubleRegistrationTomcatContextCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer", TomcatContextCustomizer.class);
assertThat(factory.getTomcatContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatProtocolHandlerCustomizerBeanIsAddedToFactory() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class, TomcatProtocolHandlerCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getTomcatProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void tomcatProtocolHandlerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(HttpHandlerConfiguration.class,
DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration.class)
.withPropertyValues("server.port: 0");
runner.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getTomcatProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void jettyServerCustomizerBeanIsAddedToFactory() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
.withUserConfiguration(JettyServerCustomizerConfiguration.class, HttpHandlerConfiguration.class)
.run((context) -> {
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
assertThat(factory.getServerCustomizers()).hasSize(1);
});
}
@Test
void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class,
HttpHandlerConfiguration.class)
.withPropertyValues("server.port=0")
.run((context) -> {
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
JettyServerCustomizer customizer = context.getBean("serverCustomizer", JettyServerCustomizer.class);
assertThat(factory.getServerCustomizers()).contains(customizer);
then(customizer).should().customize(any(Server.class));
});
}
@Test
void undertowBuilderCustomizerBeanIsAddedToFactory() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class, Server.class))
.withUserConfiguration(UndertowBuilderCustomizerConfiguration.class, HttpHandlerConfiguration.class)
.run((context) -> {
UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class);
assertThat(factory.getBuilderCustomizers()).hasSize(1);
});
}
@Test
void undertowBuilderCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class, Server.class))
.withUserConfiguration(DoubleRegistrationUndertowBuilderCustomizerConfiguration.class,
HttpHandlerConfiguration.class)
.withPropertyValues("server.port: 0")
.run((context) -> {
UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class);
UndertowBuilderCustomizer customizer = context.getBean("builderCustomizer",
UndertowBuilderCustomizer.class);
assertThat(factory.getBuilderCustomizers()).contains(customizer);
then(customizer).should().customize(any(Builder.class));
});
}
@Test
void nettyServerCustomizerBeanIsAddedToFactory() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, Server.class, Undertow.class))
.withUserConfiguration(NettyServerCustomizerConfiguration.class, HttpHandlerConfiguration.class)
.run((context) -> {
NettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);
assertThat(factory.getServerCustomizers()).hasSize(1);
});
}
@Test
void nettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(Tomcat.class, Server.class, Undertow.class))
.withUserConfiguration(DoubleRegistrationNettyServerCustomizerConfiguration.class,
HttpHandlerConfiguration.class)
.withPropertyValues("server.port: 0")
.run((context) -> {
NettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);
NettyServerCustomizer customizer = context.getBean("serverCustomizer", NettyServerCustomizer.class);
assertThat(factory.getServerCustomizers()).contains(customizer);
then(customizer).should().apply(any(HttpServer.class));
});
}
@Test
void forwardedHeaderTransformerShouldBeConfigured() {
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=framework", "server.port=0")
.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));
}
@Test
void forwardedHeaderTransformerWhenStrategyNotFilterShouldNotBeConfigured() {
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=native", "server.port=0")
.run((context) -> assertThat(context).doesNotHaveBean(ForwardedHeaderTransformer.class));
}
@Test
void forwardedHeaderTransformerWhenAlreadyRegisteredShouldBackOff() {
this.contextRunner
.withUserConfiguration(ForwardedHeaderTransformerConfiguration.class, HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=framework", "server.port=0")
.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));
}
@Configuration(proxyBeanMethods = false)
static class HttpHandlerConfiguration {
@Bean
HttpHandler httpHandler() {
return mock(HttpHandler.class);
}
}
@Configuration(proxyBeanMethods = false)
static class TooManyHttpHandlers {
@Bean
HttpHandler additionalHttpHandler() {
return mock(HttpHandler.class);
}
}
@Configuration(proxyBeanMethods = false)
static class ReactiveWebServerCustomization {
@Bean
WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> reactiveWebServerCustomizer() {
return (factory) -> factory.setPort(9000);
}
}
@Configuration(proxyBeanMethods = false)
static class MockWebServerConfiguration {
@Bean
MockReactiveWebServerFactory mockReactiveWebServerFactory() {
return new MockReactiveWebServerFactory();
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatConnectorCustomizerConfiguration {
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return mock(TomcatConnectorCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatConnectorCustomizerConfiguration {
private final TomcatConnectorCustomizer customizer = mock(TomcatConnectorCustomizer.class);
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addConnectorCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatContextCustomizerConfiguration {
@Bean
TomcatContextCustomizer contextCustomizer() {
return mock(TomcatContextCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatContextCustomizerConfiguration {
private final TomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);
@Bean
TomcatContextCustomizer contextCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addContextCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatProtocolHandlerCustomizerConfiguration {
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return mock(TomcatProtocolHandlerCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration {
private final TomcatProtocolHandlerCustomizer<?> customizer = mock(TomcatProtocolHandlerCustomizer.class);
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addProtocolHandlerCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class JettyServerCustomizerConfiguration {
@Bean
JettyServerCustomizer serverCustomizer() {
return (server) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationJettyServerCustomizerConfiguration {
private final JettyServerCustomizer customizer = mock(JettyServerCustomizer.class);
@Bean
JettyServerCustomizer serverCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<JettyReactiveWebServerFactory> jettyCustomizer() {
return (jetty) -> jetty.addServerCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class UndertowBuilderCustomizerConfiguration {
@Bean
UndertowBuilderCustomizer builderCustomizer() {
return (builder) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationUndertowBuilderCustomizerConfiguration {
private final UndertowBuilderCustomizer customizer = mock(UndertowBuilderCustomizer.class);
@Bean
UndertowBuilderCustomizer builderCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<UndertowReactiveWebServerFactory> undertowCustomizer() {
return (undertow) -> undertow.addBuilderCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class UndertowDeploymentInfoCustomizerConfiguration {
@Bean
UndertowDeploymentInfoCustomizer deploymentInfoCustomizer() {
return (deploymentInfo) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class NettyServerCustomizerConfiguration {
@Bean
NettyServerCustomizer serverCustomizer() {
return (server) -> server;
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationNettyServerCustomizerConfiguration {
private final NettyServerCustomizer customizer = mock(NettyServerCustomizer.class);
DoubleRegistrationNettyServerCustomizerConfiguration() {
given(this.customizer.apply(any(HttpServer.class))).willAnswer((invocation) -> invocation.getArgument(0));
}
@Bean
NettyServerCustomizer serverCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<NettyReactiveWebServerFactory> nettyCustomizer() {
return (netty) -> netty.addServerCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class ForwardedHeaderTransformerConfiguration {
@Bean
ForwardedHeaderTransformer testForwardedHeaderTransformer() {
return new ForwardedHeaderTransformer();
}
}
}

View File

@@ -61,7 +61,7 @@ import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext;
import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter;
import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -36,8 +36,8 @@ import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.server.reactive.netty.NettyReactiveWebServerAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.system.CapturedOutput;
@@ -86,7 +86,7 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
private final LogIdFilter logIdFilter = new LogIdFilter();
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class,
.withConfiguration(AutoConfigurations.of(NettyReactiveWebServerAutoConfiguration.class,
HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class, ErrorWebFluxAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, MustacheAutoConfiguration.class))
.withPropertyValues("spring.main.web-application-type=reactive", "server.port=0")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.jetty;
import java.time.Duration;
import java.util.concurrent.Executor;
@@ -28,7 +28,7 @@ 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 org.springframework.boot.web.server.jetty.ConfigurableJettyWebServerFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.assertArg;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.jetty;
import java.io.File;
import java.io.IOException;
@@ -48,9 +48,9 @@ import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.server.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.server.jetty.JettyWebServer;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils;

View File

@@ -0,0 +1,187 @@
/*
* Copyright 2012-2025 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.server.reactive;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.ssl.DefaultSslBundleRegistry;
import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.server.adapter.ForwardedHeaderTransformer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Base class for testing sub-classes of {@link ReactiveWebServerConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
// @DirtiesUrlFactories
public abstract class AbstractReactiveWebServerAutoConfigurationTests {
private final ReactiveWebApplicationContextRunner mockServerRunner;
protected final ReactiveWebApplicationContextRunner serverRunner;
protected AbstractReactiveWebServerAutoConfigurationTests(Class<?> serverAutoConfiguration) {
ReactiveWebApplicationContextRunner common = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(serverAutoConfiguration));
this.serverRunner = common.withPropertyValues("server.port=0")
.withUserConfiguration(HttpHandlerConfiguration.class);
this.mockServerRunner = common.withUserConfiguration(MockWebServerConfiguration.class);
}
@Test
void createFromConfigClass() {
this.mockServerRunner.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class)
.run((context) -> {
assertThat(context.getBeansOfType(ReactiveWebServerFactory.class)).hasSize(1);
assertThat(context.getBeansOfType(WebServerFactoryCustomizer.class)).hasSizeGreaterThanOrEqualTo(1);
assertThat(context.getBeansOfType(ReactiveWebServerFactoryCustomizer.class)).hasSize(1);
});
}
@Test
void missingHttpHandler() {
this.mockServerRunner.withUserConfiguration(MockWebServerConfiguration.class)
.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)
.rootCause()
.hasMessageContaining("missing HttpHandler bean"));
}
@Test
void multipleHttpHandler() {
this.mockServerRunner
.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,
TooManyHttpHandlers.class)
.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)
.rootCause()
.hasMessageContaining("multiple HttpHandler beans : httpHandler,additionalHttpHandler"));
}
@Test
void customizeReactiveWebServer() {
this.mockServerRunner
.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,
ReactiveWebServerCustomization.class)
.run((context) -> assertThat(context.getBean(MockReactiveWebServerFactory.class).getPort())
.isEqualTo(9000));
}
@Test
void webServerFailsWithInvalidSslBundle() {
this.serverRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withBean(WebServerFactoryCustomizer.class,
() -> (WebServerFactoryCustomizer<ConfigurableWebServerFactory>) (factory) -> factory
.setSslBundles(new DefaultSslBundleRegistry()))
.withPropertyValues("server.ssl.bundle=test-bundle")
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure().getCause()).isInstanceOf(NoSuchSslBundleException.class)
.withFailMessage("test");
});
}
@Test
void forwardedHeaderTransformerShouldBeConfigured() {
this.mockServerRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=framework", "server.port=0")
.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));
}
@Test
void forwardedHeaderTransformerWhenStrategyNotFilterShouldNotBeConfigured() {
this.mockServerRunner.withUserConfiguration(HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=native", "server.port=0")
.run((context) -> assertThat(context).doesNotHaveBean(ForwardedHeaderTransformer.class));
}
@Test
void forwardedHeaderTransformerWhenAlreadyRegisteredShouldBackOff() {
this.mockServerRunner
.withUserConfiguration(ForwardedHeaderTransformerConfiguration.class, HttpHandlerConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=framework", "server.port=0")
.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));
}
@Configuration(proxyBeanMethods = false)
static class HttpHandlerConfiguration {
@Bean
HttpHandler httpHandler() {
return mock(HttpHandler.class);
}
}
@Configuration(proxyBeanMethods = false)
static class TooManyHttpHandlers {
@Bean
HttpHandler additionalHttpHandler() {
return mock(HttpHandler.class);
}
}
@Configuration(proxyBeanMethods = false)
static class ReactiveWebServerCustomization {
@Bean
WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> reactiveWebServerCustomizer() {
return (factory) -> factory.setPort(9000);
}
}
@Configuration(proxyBeanMethods = false)
static class MockWebServerConfiguration {
@Bean
MockReactiveWebServerFactory mockReactiveWebServerFactory() {
return new MockReactiveWebServerFactory();
}
}
@Configuration(proxyBeanMethods = false)
static class ForwardedHeaderTransformerConfiguration {
@Bean
ForwardedHeaderTransformer testForwardedHeaderTransformer() {
return new ForwardedHeaderTransformer();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
package org.springframework.boot.autoconfigure.web.server.reactive;
import java.net.InetAddress;
@@ -24,9 +24,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.ssl.DefaultSslBundleRegistry;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.assertArg;

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2012-2025 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.server.reactive.jetty;
import jakarta.websocket.server.ServerContainer;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.server.reactive.AbstractReactiveWebServerAutoConfigurationTests;
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.jetty.JettyServerCustomizer;
import org.springframework.boot.web.server.jetty.JettyWebServer;
import org.springframework.boot.web.server.reactive.jetty.JettyReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JettyReactiveWebServerAutoConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
class JettyReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {
JettyReactiveWebServerAutoConfigurationTests() {
super(JettyReactiveWebServerAutoConfiguration.class);
}
@Test
void jettyServerCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(JettyServerCustomizerConfiguration.class).run((context) -> {
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
assertThat(factory.getServerCustomizers())
.contains(context.getBean("serverCustomizer", JettyServerCustomizer.class));
});
}
@Test
void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class)
.run((context) -> {
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
JettyServerCustomizer customizer = context.getBean("serverCustomizer", JettyServerCustomizer.class);
assertThat(factory.getServerCustomizers()).contains(customizer);
then(customizer).should().customize(any(Server.class));
});
}
@Test
void webSocketServerContainerIsAvailableFromServletContext() {
this.serverRunner.run((context) -> {
WebServer webServer = ((ReactiveWebServerApplicationContext) context.getSourceApplicationContext())
.getWebServer();
ServletContextHandler servletContextHandler = (ServletContextHandler) ((StatisticsHandler) ((JettyWebServer) webServer)
.getServer()
.getHandler()).getHandler();
Object serverContainer = servletContextHandler.getContext()
.getAttribute("jakarta.websocket.server.ServerContainer");
assertThat(serverContainer).isInstanceOf(ServerContainer.class);
});
}
@Configuration(proxyBeanMethods = false)
static class JettyServerCustomizerConfiguration {
@Bean
JettyServerCustomizer serverCustomizer() {
return (server) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationJettyServerCustomizerConfiguration {
private final JettyServerCustomizer customizer = mock(JettyServerCustomizer.class);
@Bean
JettyServerCustomizer serverCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<JettyReactiveWebServerFactory> jettyCustomizer() {
return (jetty) -> jetty.addServerCustomizers(this.customizer);
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2012-2025 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.server.reactive.netty;
import org.junit.jupiter.api.Test;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.web.server.reactive.AbstractReactiveWebServerAutoConfigurationTests;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.netty.NettyServerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link NettyReactiveWebServerAutoConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
// @DirtiesUrlFactories
class NettyReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {
NettyReactiveWebServerAutoConfigurationTests() {
super(NettyReactiveWebServerAutoConfiguration.class);
}
@Test
void nettyServerCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(NettyServerCustomizerConfiguration.class).run((context) -> {
NettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);
assertThat(factory.getServerCustomizers())
.contains(context.getBean("serverCustomizer", NettyServerCustomizer.class));
});
}
@Test
void nettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationNettyServerCustomizerConfiguration.class)
.run((context) -> {
NettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);
NettyServerCustomizer customizer = context.getBean("serverCustomizer", NettyServerCustomizer.class);
assertThat(factory.getServerCustomizers()).contains(customizer);
then(customizer).should().apply(any(HttpServer.class));
});
}
@Configuration(proxyBeanMethods = false)
static class NettyServerCustomizerConfiguration {
@Bean
NettyServerCustomizer serverCustomizer() {
return (server) -> server;
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationNettyServerCustomizerConfiguration {
private final NettyServerCustomizer customizer = mock(NettyServerCustomizer.class);
DoubleRegistrationNettyServerCustomizerConfiguration() {
given(this.customizer.apply(any(HttpServer.class))).willAnswer((invocation) -> invocation.getArgument(0));
}
@Bean
NettyServerCustomizer serverCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<NettyReactiveWebServerFactory> nettyCustomizer() {
return (netty) -> netty.addServerCustomizers(this.customizer);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded;
package org.springframework.boot.autoconfigure.web.server.reactive.netty;
import java.time.Duration;
import java.util.Map;
@@ -32,8 +32,8 @@ import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
import org.springframework.boot.web.server.reactive.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.netty.NettyServerCustomizer;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.unit.DataSize;
@@ -45,20 +45,20 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
/**
* Tests for {@link NettyWebServerFactoryCustomizer}.
* Tests for {@link NettyReactiveWebServerFactoryCustomizer}.
*
* @author Brian Clozel
* @author Artsiom Yudovin
* @author Leo Li
*/
@ExtendWith(MockitoExtension.class)
class NettyWebServerFactoryCustomizerTests {
class NettyReactiveWebServerFactoryCustomizerTests {
private MockEnvironment environment;
private ServerProperties serverProperties;
private NettyWebServerFactoryCustomizer customizer;
private NettyReactiveWebServerFactoryCustomizer customizer;
@Captor
private ArgumentCaptor<NettyServerCustomizer> customizerCaptor;
@@ -68,7 +68,7 @@ class NettyWebServerFactoryCustomizerTests {
this.environment = new MockEnvironment();
this.serverProperties = new ServerProperties();
ConfigurationPropertySources.attach(this.environment);
this.customizer = new NettyWebServerFactoryCustomizer(this.environment, this.serverProperties);
this.customizer = new NettyReactiveWebServerFactoryCustomizer(this.environment, this.serverProperties);
}
@Test

View File

@@ -0,0 +1,227 @@
/*
* Copyright 2012-2025 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.server.reactive.tomcat;
import jakarta.servlet.ServletContext;
import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.server.reactive.AbstractReactiveWebServerAutoConfigurationTests;
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.server.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatWebServer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link TomcatReactiveWebServerAutoConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
class TomcatReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {
TomcatReactiveWebServerAutoConfigurationTests() {
super(TomcatReactiveWebServerAutoConfiguration.class);
}
@Test
void tomcatConnectorCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatConnectorCustomizerConfiguration.class).run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatConnectorCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatConnectorCustomizerConfiguration.class)
.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatContextCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatContextCustomizerConfiguration.class).run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer", TomcatContextCustomizer.class);
assertThat(factory.getContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatContextCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatContextCustomizerConfiguration.class)
.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer",
TomcatContextCustomizer.class);
assertThat(factory.getContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatProtocolHandlerCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatProtocolHandlerCustomizerConfiguration.class).run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void tomcatProtocolHandlerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration.class)
.run((context) -> {
TomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void webSocketServerContainerIsAvailableFromServletContext() {
this.serverRunner.run((context) -> {
WebServer webServer = ((ReactiveWebServerApplicationContext) context.getSourceApplicationContext())
.getWebServer();
ServletContext servletContext = findContext(((TomcatWebServer) webServer).getTomcat()).getServletContext();
Object serverContainer = servletContext.getAttribute("jakarta.websocket.server.ServerContainer");
assertThat(serverContainer).isInstanceOf(ServerContainer.class);
});
}
private static Context findContext(Tomcat tomcat) {
for (Container child : tomcat.getHost().findChildren()) {
if (child instanceof Context context) {
return context;
}
}
throw new IllegalStateException("The Host does not contain a Context");
}
@Configuration(proxyBeanMethods = false)
static class TomcatConnectorCustomizerConfiguration {
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return mock(TomcatConnectorCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatConnectorCustomizerConfiguration {
private final TomcatConnectorCustomizer customizer = mock(TomcatConnectorCustomizer.class);
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addConnectorCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatContextCustomizerConfiguration {
@Bean
TomcatContextCustomizer contextCustomizer() {
return mock(TomcatContextCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatContextCustomizerConfiguration {
private final TomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);
@Bean
TomcatContextCustomizer contextCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addContextCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatProtocolHandlerCustomizerConfiguration {
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return mock(TomcatProtocolHandlerCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration {
private final TomcatProtocolHandlerCustomizer<?> customizer = mock(TomcatProtocolHandlerCustomizer.class);
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addProtocolHandlerCustomizers(this.customizer);
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2012-2025 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.server.reactive.undertow;
import io.undertow.Undertow.Builder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.server.reactive.AbstractReactiveWebServerAutoConfigurationTests;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.reactive.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.server.servlet.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.server.undertow.UndertowBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link UndertowReactiveWebServerAutoConfiguration}.
*
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Scott Frederick
*/
class UndertowReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {
UndertowReactiveWebServerAutoConfigurationTests() {
super(UndertowReactiveWebServerAutoConfiguration.class);
}
@Test
void undertowBuilderCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(UndertowBuilderCustomizerConfiguration.class).run((context) -> {
UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class);
assertThat(factory.getBuilderCustomizers())
.contains(context.getBean("builderCustomizer", UndertowBuilderCustomizer.class));
});
}
@Test
void undertowBuilderCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationUndertowBuilderCustomizerConfiguration.class)
.run((context) -> {
UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class);
UndertowBuilderCustomizer customizer = context.getBean("builderCustomizer",
UndertowBuilderCustomizer.class);
assertThat(factory.getBuilderCustomizers()).contains(customizer);
then(customizer).should().customize(any(Builder.class));
});
}
@Configuration(proxyBeanMethods = false)
static class UndertowBuilderCustomizerConfiguration {
@Bean
UndertowBuilderCustomizer builderCustomizer() {
return (builder) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationUndertowBuilderCustomizerConfiguration {
private final UndertowBuilderCustomizer customizer = mock(UndertowBuilderCustomizer.class);
@Bean
UndertowBuilderCustomizer builderCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<UndertowReactiveWebServerFactory> undertowCustomizer() {
return (undertow) -> undertow.addBuilderCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class UndertowDeploymentInfoCustomizerConfiguration {
@Bean
UndertowDeploymentInfoCustomizer deploymentInfoCustomizer() {
return (deploymentInfo) -> {
};
}
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright 2012-2025 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.server.servlet;
import java.io.IOException;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.websocket.server.ServerContainer;
import jakarta.websocket.server.ServerEndpoint;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;
import org.springframework.boot.web.server.servlet.MockServletWebServerFactory;
import org.springframework.boot.web.server.servlet.ServletContextInitializer;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.ForwardedHeaderFilter;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Base class for testing sub-classes of {@link ServletWebServerConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Raheela Aslam
* @author Madhura Bhave
*/
public abstract class AbstractServletWebServerAutoConfigurationTests {
private final WebApplicationContextRunner mockServerRunner;
protected final WebApplicationContextRunner serverRunner;
protected AbstractServletWebServerAutoConfigurationTests(Class<?> serverAutoConfiguration) {
WebApplicationContextRunner common = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(serverAutoConfiguration));
this.serverRunner = common.withPropertyValues("server.port=0");
this.mockServerRunner = common.withUserConfiguration(MockWebServerConfiguration.class);
}
@Test
void createFromConfigClass() {
this.mockServerRunner
.run((context) -> assertThat(context).hasSingleBean(ServletWebServerFactoryCustomizer.class));
}
@Test
void webServerHasNoServletContext() {
this.mockServerRunner.withUserConfiguration(EnsureWebServerHasNoServletContext.class)
.run((context) -> assertThat(context).hasNotFailed());
}
@Test
void webServerFactoryCustomizerBeansAreCalledToCustomizeWebServerFactory() {
this.mockServerRunner
.withBean(WebServerFactoryCustomizer.class,
() -> (WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>) (factory) -> factory
.setPort(9000))
.run((context) -> assertThat(context.getBean(MockServletWebServerFactory.class).getPort()).isEqualTo(9000));
}
@Test
void initParametersAreConfiguredOnTheServletContext() {
this.mockServerRunner
.withPropertyValues("server.servlet.context-parameters.a:alpha",
"server.servlet.context-parameters.b:bravo")
.run((context) -> {
ServletContext servletContext = context.getServletContext();
assertThat(servletContext.getInitParameter("a")).isEqualTo("alpha");
assertThat(servletContext.getInitParameter("b")).isEqualTo("bravo");
});
}
@Test
void forwardedHeaderFilterShouldBeConfigured() {
this.mockServerRunner.withPropertyValues("server.forward-headers-strategy=framework").run((context) -> {
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(filter).extracting("relativeRedirects").isEqualTo(false);
});
}
@Test
void forwardedHeaderFilterWhenStrategyNotFilterShouldNotBeConfigured() {
this.mockServerRunner.withPropertyValues("server.forward-headers-strategy=native")
.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class));
}
@Test
void forwardedHeaderFilterWhenFilterAlreadyRegisteredShouldBackOff() {
this.mockServerRunner.withUserConfiguration(ForwardedHeaderFilterConfiguration.class)
.withPropertyValues("server.forward-headers-strategy=framework")
.run((context) -> assertThat(context).hasSingleBean(FilterRegistrationBean.class));
}
@Test
void cookieSameSiteSuppliersAreApplied() {
this.mockServerRunner.withUserConfiguration(CookieSameSiteSupplierConfiguration.class).run((context) -> {
ConfigurableServletWebServerFactory webServerFactory = context
.getBean(ConfigurableServletWebServerFactory.class);
assertThat(webServerFactory.getSettings().getCookieSameSiteSuppliers()).hasSize(2);
});
}
@Test
void webSocketServerContainerIsAvailableFromServletContext() {
this.serverRunner.run((context) -> {
Object serverContainer = context.getServletContext()
.getAttribute("jakarta.websocket.server.ServerContainer");
assertThat(serverContainer).isInstanceOf(ServerContainer.class);
});
}
@Test
void webSocketUpgradeDoesNotPreventAFilterFromRejectingTheRequest() {
this.serverRunner
.withBean("testEndpointRegistrar", ServletContextInitializer.class, () -> TestEndpoint::register)
.withUserConfiguration(UnauthorizedFilterConfiguration.class)
.run((context) -> {
TestEndpoint.register(context.getServletContext());
WebServer webServer = ((WebServerApplicationContext) context.getSourceApplicationContext())
.getWebServer();
int port = webServer.getPort();
TestRestTemplate rest = new TestRestTemplate();
RequestEntity<Void> request = RequestEntity.get("http://localhost:" + port)
.header("Upgrade", "websocket")
.header("Connection", "upgrade")
.header("Sec-WebSocket-Version", "13")
.header("Sec-WebSocket-Key", "key")
.build();
ResponseEntity<Void> response = rest.exchange(request, Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
});
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnExpression("true")
static class MockWebServerConfiguration {
@Bean
ServletWebServerFactory webServerFactory() {
return new MockServletWebServerFactory();
}
}
@Component
static class EnsureWebServerHasNoServletContext implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ConfigurableServletWebServerFactory) {
MockServletWebServerFactory webServerFactory = (MockServletWebServerFactory) bean;
assertThat(webServerFactory.getServletContext()).isNull();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
@Configuration(proxyBeanMethods = false)
static class ForwardedHeaderFilterConfiguration {
@Bean
FilterRegistrationBean<ForwardedHeaderFilter> testForwardedHeaderFilter() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
return new FilterRegistrationBean<>(filter);
}
}
@Configuration(proxyBeanMethods = false)
static class CookieSameSiteSupplierConfiguration {
@Bean
CookieSameSiteSupplier cookieSameSiteSupplier1() {
return CookieSameSiteSupplier.ofLax().whenHasName("test1");
}
@Bean
CookieSameSiteSupplier cookieSameSiteSupplier2() {
return CookieSameSiteSupplier.ofNone().whenHasName("test2");
}
}
@ServerEndpoint("/")
public static class TestEndpoint {
static void register(ServletContext context) {
try {
ServerContainer serverContainer = (ServerContainer) context
.getAttribute("jakarta.websocket.server.ServerContainer");
if (serverContainer != null) {
serverContainer.addEndpoint(TestEndpoint.class);
}
}
catch (Exception ex) {
// Continue
}
}
}
@Configuration(proxyBeanMethods = false)
static class UnauthorizedFilterConfiguration {
@Bean
FilterRegistrationBean<Filter> unauthorizedFilter() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(new Filter() {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
((HttpServletResponse) response).sendError(HttpStatus.UNAUTHORIZED.value());
}
});
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
registration.addUrlPatterns("/*");
registration.setDispatcherTypes(DispatcherType.REQUEST);
return registration;
}
@Bean
ServletRegistrationBean<HttpServlet> basicServlet() {
ServletRegistrationBean<HttpServlet> registration = new ServletRegistrationBean<>(new HttpServlet() {
});
registration.addUrlMappings("/");
return registration;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet;
import java.io.File;
import java.nio.charset.StandardCharsets;
@@ -35,8 +35,8 @@ import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Jsp;
import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.server.servlet.Jsp;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet;
import java.util.stream.Stream;
@@ -26,13 +26,13 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2012-2025 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.server.servlet.jetty;
import java.util.Map;
import jakarta.servlet.Filter;
import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.eclipse.jetty.server.Server;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.web.server.servlet.AbstractServletWebServerAutoConfigurationTests;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.jetty.JettyServerCustomizer;
import org.springframework.boot.web.server.servlet.ServletContextInitializer;
import org.springframework.boot.web.server.servlet.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.servlet.AbstractFilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Base class for testing sub-classes of {@link JettyServletWebServerAutoConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Raheela Aslam
* @author Madhura Bhave
*/
class JettyServletWebServerAutoConfigurationTests extends AbstractServletWebServerAutoConfigurationTests {
protected JettyServletWebServerAutoConfigurationTests() {
super(JettyServletWebServerAutoConfiguration.class);
}
@Test
void jettyServerCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(JettyServerCustomizerConfiguration.class).run((context) -> {
JettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);
assertThat(factory.getServerCustomizers())
.contains(context.getBean("serverCustomizer", JettyServerCustomizer.class));
});
}
@Test
void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class)
.run((context) -> {
JettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);
JettyServerCustomizer customizer = context.getBean("serverCustomizer", JettyServerCustomizer.class);
assertThat(factory.getServerCustomizers()).contains(customizer);
then(customizer).should().customize(any(Server.class));
});
}
@Test
void jettyWebSocketUpgradeFilterIsAddedToServletContex() {
this.serverRunner.run((context) -> assertThat(
context.getServletContext().getFilterRegistration(WebSocketUpgradeFilter.class.getName()))
.isNotNull());
}
@Test
@SuppressWarnings("rawtypes")
void jettyWebSocketUpgradeFilterIsNotExposedAsABean() {
this.serverRunner.run((context) -> {
Map<String, Filter> filters = context.getBeansOfType(Filter.class);
assertThat(filters.values()).noneMatch(WebSocketUpgradeFilter.class::isInstance);
Map<String, AbstractFilterRegistrationBean> filterRegistrations = context
.getBeansOfType(AbstractFilterRegistrationBean.class);
assertThat(filterRegistrations.values()).extracting(AbstractFilterRegistrationBean::getFilter)
.noneMatch(WebSocketUpgradeFilter.class::isInstance);
});
}
@Test
void jettyWebSocketUpgradeFilterServletContextInitializerBacksOffWhenBeanWithSameNameIsDefined() {
this.serverRunner
.withUserConfiguration(CustomWebSocketUpgradeFilterServletContextInitializerConfiguration.class)
.run((context) -> {
BeanDefinition definition = context.getBeanFactory()
.getBeanDefinition("websocketUpgradeFilterServletContextInitializer");
assertThat(definition.getFactoryBeanName())
.contains("CustomWebSocketUpgradeFilterServletContextInitializerConfiguration");
});
}
@Configuration(proxyBeanMethods = false)
static class JettyServerCustomizerConfiguration {
@Bean
JettyServerCustomizer serverCustomizer() {
return (server) -> {
};
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationJettyServerCustomizerConfiguration {
private final JettyServerCustomizer customizer = mock(JettyServerCustomizer.class);
@Bean
JettyServerCustomizer serverCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<JettyServletWebServerFactory> jettyCustomizer() {
return (jetty) -> jetty.addServerCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class CustomWebSocketUpgradeFilterServletContextInitializerConfiguration {
@Bean
ServletContextInitializer websocketUpgradeFilterServletContextInitializer() {
return (servletContext) -> {
};
}
}
}

View File

@@ -0,0 +1,228 @@
/*
* Copyright 2012-2025 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.server.servlet.tomcat;
import jakarta.servlet.Filter;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.server.servlet.AbstractServletWebServerAutoConfigurationTests;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.server.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ForwardedHeaderFilter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link TomcatServletWebServerAutoConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Raheela Aslam
* @author Madhura Bhave
*/
class TomcatServletWebServerAutoConfigurationTests extends AbstractServletWebServerAutoConfigurationTests {
TomcatServletWebServerAutoConfigurationTests() {
super(TomcatServletWebServerAutoConfiguration.class);
}
@Test
void tomcatConnectorCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatConnectorCustomizerConfiguration.class).run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatConnectorCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatConnectorCustomizerConfiguration.class)
.run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatConnectorCustomizer customizer = context.getBean("connectorCustomizer",
TomcatConnectorCustomizer.class);
assertThat(factory.getConnectorCustomizers()).contains(customizer);
then(customizer).should().customize(any(Connector.class));
});
}
@Test
void tomcatContextCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatContextCustomizerConfiguration.class).run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer", TomcatContextCustomizer.class);
assertThat(factory.getContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatContextCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatContextCustomizerConfiguration.class)
.run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatContextCustomizer customizer = context.getBean("contextCustomizer",
TomcatContextCustomizer.class);
assertThat(factory.getContextCustomizers()).contains(customizer);
then(customizer).should().customize(any(Context.class));
});
}
@Test
void tomcatProtocolHandlerCustomizerBeanIsAddedToFactory() {
this.serverRunner.withUserConfiguration(TomcatProtocolHandlerCustomizerConfiguration.class).run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void tomcatProtocolHandlerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
this.serverRunner.withUserConfiguration(DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration.class)
.run((context) -> {
TomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);
TomcatProtocolHandlerCustomizer<?> customizer = context.getBean("protocolHandlerCustomizer",
TomcatProtocolHandlerCustomizer.class);
assertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);
then(customizer).should().customize(any());
});
}
@Test
void whenUsingFrameworkForwardHeadersStrategyAndRelativeRedirectsAreEnabledThenFilterIsConfiguredToUseRelativeRedirects() {
this.serverRunner
.withPropertyValues("server.forward-headers-strategy=framework",
"server.tomcat.use-relative-redirects=true", "server.port=0")
.run((context) -> {
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(filter).extracting("relativeRedirects").isEqualTo(true);
});
}
@Test
void whenUsingFrameworkForwardHeadersStrategyAndNotUsingRelativeRedirectsThenFilterIsNotConfiguredToUseRelativeRedirects() {
this.serverRunner
.withPropertyValues("server.forward-headers-strategy=framework",
"server.tomcat.use-relative-redirects=false", "server.port=0")
.run((context) -> {
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(filter).extracting("relativeRedirects").isEqualTo(false);
});
}
@Configuration(proxyBeanMethods = false)
static class TomcatConnectorCustomizerConfiguration {
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return mock(TomcatConnectorCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatConnectorCustomizerConfiguration {
private final TomcatConnectorCustomizer customizer = mock(TomcatConnectorCustomizer.class);
@Bean
TomcatConnectorCustomizer connectorCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addConnectorCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatContextCustomizerConfiguration {
@Bean
TomcatContextCustomizer contextCustomizer() {
return mock(TomcatContextCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatContextCustomizerConfiguration {
private final TomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);
@Bean
TomcatContextCustomizer contextCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addContextCustomizers(this.customizer);
}
}
@Configuration(proxyBeanMethods = false)
static class TomcatProtocolHandlerCustomizerConfiguration {
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return mock(TomcatProtocolHandlerCustomizer.class);
}
}
@Configuration(proxyBeanMethods = false)
static class DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration {
private final TomcatProtocolHandlerCustomizer<?> customizer = mock(TomcatProtocolHandlerCustomizer.class);
@Bean
TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return this.customizer;
}
@Bean
WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addProtocolHandlerCustomizers(this.customizer);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet;
package org.springframework.boot.autoconfigure.web.server.servlet.tomcat;
import org.apache.catalina.Context;
import org.junit.jupiter.api.BeforeEach;
@@ -24,8 +24,8 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.servlet.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.tomcat.TomcatWebServer;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;

Some files were not shown because too many files have changed in this diff Show More