diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java index 78f7bd2ecd..5d7cb49cb5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java @@ -25,11 +25,14 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 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.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.server.ReactiveWebServerFactory; import org.springframework.context.annotation.Bean; @@ -45,6 +48,7 @@ import org.springframework.http.client.reactive.ReactorResourceFactory; * * @author Brian Clozel * @author Raheela Aslam + * @author Sergey Serdyuk */ abstract class ReactiveWebServerFactoryConfiguration { @@ -105,8 +109,11 @@ abstract class ReactiveWebServerFactoryConfiguration { @Bean public JettyReactiveWebServerFactory jettyReactiveWebServerFactory( - JettyResourceFactory resourceFactory) { + JettyResourceFactory resourceFactory, + ObjectProvider serverCustomizers) { JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory(); + serverFactory.getServerCustomizers().addAll( + serverCustomizers.orderedStream().collect(Collectors.toList())); serverFactory.setResourceFactory(resourceFactory); return serverFactory; } @@ -119,8 +126,15 @@ abstract class ReactiveWebServerFactoryConfiguration { static class EmbeddedUndertow { @Bean - public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory() { - return new UndertowReactiveWebServerFactory(); + public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory( + ObjectProvider deploymentInfoCustomizers, + ObjectProvider builderCustomizers) { + UndertowReactiveWebServerFactory factory = new UndertowReactiveWebServerFactory(); + factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers + .orderedStream().collect(Collectors.toList())); + factory.getBuilderCustomizers().addAll( + builderCustomizers.orderedStream().collect(Collectors.toList())); + return factory; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryConfiguration.java index fceccda369..d5f294775e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryConfiguration.java @@ -32,11 +32,14 @@ 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.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; @@ -54,6 +57,7 @@ import org.springframework.context.annotation.Configuration; * @author Brian Clozel * @author Stephane Nicoll * @author Raheela Asalm + * @author Sergey Serdyuk */ @Configuration(proxyBeanMethods = false) class ServletWebServerFactoryConfiguration { @@ -93,8 +97,12 @@ class ServletWebServerFactoryConfiguration { public static class EmbeddedJetty { @Bean - public JettyServletWebServerFactory JettyServletWebServerFactory() { - return new JettyServletWebServerFactory(); + public JettyServletWebServerFactory JettyServletWebServerFactory( + ObjectProvider serverCustomizers) { + JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); + factory.getServerCustomizers().addAll( + serverCustomizers.orderedStream().collect(Collectors.toList())); + return factory; } } @@ -109,8 +117,15 @@ class ServletWebServerFactoryConfiguration { public static class EmbeddedUndertow { @Bean - public UndertowServletWebServerFactory undertowServletWebServerFactory() { - return new UndertowServletWebServerFactory(); + public UndertowServletWebServerFactory undertowServletWebServerFactory( + ObjectProvider deploymentInfoCustomizers, + ObjectProvider builderCustomizers) { + UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); + factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers + .orderedStream().collect(Collectors.toList())); + factory.getBuilderCustomizers().addAll( + builderCustomizers.orderedStream().collect(Collectors.toList())); + return factory; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java index f3efd04152..887c0e2125 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java @@ -16,15 +16,24 @@ package org.springframework.boot.autoconfigure.web.reactive; +import org.apache.catalina.startup.Tomcat; +import org.eclipse.jetty.server.Server; import org.junit.Test; import org.mockito.Mockito; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; 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; @@ -149,6 +158,59 @@ public class ReactiveWebServerFactoryAutoConfigurationTests { }); } + @Test + public 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 + public void undertowDeploymentInfoCustomizerBeanIsAddedToFactory() { + new ReactiveWebApplicationContextRunner( + AnnotationConfigReactiveWebApplicationContext::new) + .withConfiguration(AutoConfigurations + .of(ReactiveWebServerFactoryAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader(Tomcat.class, + HttpServer.class, Server.class)) + .withUserConfiguration( + UndertowDeploymentInfoCustomizerConfiguration.class, + HttpHandlerConfiguration.class) + .run((context) -> { + UndertowReactiveWebServerFactory factory = context + .getBean(UndertowReactiveWebServerFactory.class); + assertThat(factory.getDeploymentInfoCustomizers()).hasSize(1); + }); + } + + @Test + public 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 public void forwardedHeaderTransformerShouldBeConfigured() { this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class) @@ -248,6 +310,42 @@ public class ReactiveWebServerFactoryAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class JettyServerCustomizerConfiguration { + + @Bean + public JettyServerCustomizer protocolHandlerCustomizer() { + return (server) -> { + + }; + } + + } + + @Configuration(proxyBeanMethods = false) + static class UndertowBuilderCustomizerConfiguration { + + @Bean + public UndertowBuilderCustomizer protocolHandlerCustomizer() { + return (builder) -> { + + }; + } + + } + + @Configuration(proxyBeanMethods = false) + static class UndertowDeploymentInfoCustomizerConfiguration { + + @Bean + public UndertowDeploymentInfoCustomizer protocolHandlerCustomizer() { + return (deploymentInfo) -> { + + }; + } + + } + @Configuration(proxyBeanMethods = false) static class ForwardedHeaderTransformerConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java index 6c62abb5f4..d3dc810e7d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java @@ -22,19 +22,28 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.startup.Tomcat; +import org.eclipse.jetty.server.Server; import org.junit.Test; +import reactor.netty.http.server.HttpServer; import org.springframework.beans.BeansException; 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.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +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.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; @@ -147,6 +156,56 @@ public class ServletWebServerFactoryAutoConfigurationTests { }); } + @Test + public void jettyServerCustomizerBeanIsAddedToFactory() { + WebApplicationContextRunner runner = new WebApplicationContextRunner( + AnnotationConfigServletWebServerApplicationContext::new) + .withClassLoader( + new FilteredClassLoader(Tomcat.class, HttpServer.class)) + .withConfiguration(AutoConfigurations + .of(ServletWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration(JettyServerCustomizerConfiguration.class); + runner.run((context) -> { + JettyServletWebServerFactory factory = context + .getBean(JettyServletWebServerFactory.class); + assertThat(factory.getServerCustomizers()).hasSize(1); + }); + } + + @Test + public void undertowDeploymentInfoCustomizerBeanIsAddedToFactory() { + WebApplicationContextRunner runner = new WebApplicationContextRunner( + AnnotationConfigServletWebServerApplicationContext::new) + .withClassLoader(new FilteredClassLoader(Tomcat.class, + HttpServer.class, Server.class)) + .withConfiguration(AutoConfigurations + .of(ServletWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration( + UndertowDeploymentInfoCustomizerConfiguration.class); + runner.run((context) -> { + UndertowServletWebServerFactory factory = context + .getBean(UndertowServletWebServerFactory.class); + assertThat(factory.getDeploymentInfoCustomizers()).hasSize(1); + }); + } + + @Test + public void undertowBuilderCustomizerBeanIsAddedToFactory() { + WebApplicationContextRunner runner = new WebApplicationContextRunner( + AnnotationConfigServletWebServerApplicationContext::new) + .withClassLoader(new FilteredClassLoader(Tomcat.class, + HttpServer.class, Server.class)) + .withConfiguration(AutoConfigurations + .of(ServletWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration( + UndertowBuilderCustomizerConfiguration.class); + runner.run((context) -> { + UndertowServletWebServerFactory factory = context + .getBean(UndertowServletWebServerFactory.class); + assertThat(factory.getBuilderCustomizers()).hasSize(1); + }); + } + @Test public void tomcatConnectorCustomizerBeanIsAddedToFactory() { WebApplicationContextRunner runner = new WebApplicationContextRunner( @@ -365,6 +424,42 @@ public class ServletWebServerFactoryAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class JettyServerCustomizerConfiguration { + + @Bean + public JettyServerCustomizer protocolHandlerCustomizer() { + return (server) -> { + + }; + } + + } + + @Configuration(proxyBeanMethods = false) + static class UndertowBuilderCustomizerConfiguration { + + @Bean + public UndertowBuilderCustomizer protocolHandlerCustomizer() { + return (builder) -> { + + }; + } + + } + + @Configuration(proxyBeanMethods = false) + static class UndertowDeploymentInfoCustomizerConfiguration { + + @Bean + public UndertowDeploymentInfoCustomizer protocolHandlerCustomizer() { + return (deploymentInfo) -> { + + }; + } + + } + @Configuration(proxyBeanMethods = false) static class ForwardedHeaderFilterConfiguration {