Add NettyServerCustomizer beans to the auto-configured factory

Closes gh-17556
This commit is contained in:
Andy Wilkinson 2019-07-17 14:51:47 +01:00
parent ea1139755d
commit dad7fb4f6d
3 changed files with 71 additions and 3 deletions

View File

@ -28,6 +28,7 @@ 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;
@ -66,10 +67,11 @@ abstract class ReactiveWebServerFactoryConfiguration {
@Bean
NettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory,
ObjectProvider<NettyRouteProvider> routes) {
ObjectProvider<NettyRouteProvider> routes, ObjectProvider<NettyServerCustomizer> serverCustomizers) {
NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();
serverFactory.setResourceFactory(resourceFactory);
routes.orderedStream().forEach((route) -> serverFactory.addRouteProviders(route));
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return serverFactory;
}

View File

@ -16,6 +16,7 @@
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;
@ -25,10 +26,14 @@ import org.junit.jupiter.api.Test;
import reactor.netty.http.server.HttpServer;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
import org.springframework.boot.logging.LogLevel;
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.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;
@ -49,6 +54,7 @@ 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.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -279,6 +285,33 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
});
}
@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)
.withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO)).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);
verify(customizer, times(1)).apply(any(HttpServer.class));
});
}
@Test
void forwardedHeaderTransformerShouldBeConfigured() {
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
@ -489,6 +522,37 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
}
@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 {

View File

@ -21,7 +21,9 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import reactor.netty.http.HttpProtocol;
import reactor.netty.http.server.HttpServer;
@ -43,7 +45,7 @@ import org.springframework.util.Assert;
*/
public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory {
private List<NettyServerCustomizer> serverCustomizers = new ArrayList<>();
private Set<NettyServerCustomizer> serverCustomizers = new LinkedHashSet<>();
private List<NettyRouteProvider> routeProviders = new ArrayList<>();
@ -85,7 +87,7 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
*/
public void setServerCustomizers(Collection<? extends NettyServerCustomizer> serverCustomizers) {
Assert.notNull(serverCustomizers, "ServerCustomizers must not be null");
this.serverCustomizers = new ArrayList<>(serverCustomizers);
this.serverCustomizers = new LinkedHashSet<>(serverCustomizers);
}
/**