diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index b5b90970d2f..c51106b1d01 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -16,6 +16,12 @@ package org.springframework.boot.web.embedded.netty; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import reactor.ipc.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; @@ -23,6 +29,7 @@ import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.server.WebServer; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; +import org.springframework.util.Assert; /** * {@link ReactiveWebServerFactory} that can be used to create {@link NettyWebServer}s. @@ -32,6 +39,8 @@ import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; */ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory { + private List nettyServerCustomizers = new ArrayList<>(); + public NettyReactiveWebServerFactory() { } @@ -47,15 +56,53 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact return new NettyWebServer(server, handlerAdapter); } + /** + * Returns a mutable collection of the {@link NettyServerCustomizer}s that will be + * applied to the Netty server builder. + * @return the customizers that will be applied + */ + public Collection getNettyServerCustomizers() { + return this.nettyServerCustomizers; + } + + /** + * Set {@link NettyServerCustomizer}s that should be applied to the Netty + * server builder. Calling this method will replace any existing customizers. + * @param nettyServerCustomizers the customizers to set + */ + public void setNettyServerCustomizers( + Collection nettyServerCustomizers) { + Assert.notNull(nettyServerCustomizers, + "NettyServerCustomizers must not be null"); + this.nettyServerCustomizers = new ArrayList<>(nettyServerCustomizers); + } + + + /** + * Add {@link NettyServerCustomizer}s that should applied while building the server. + * @param nettyServerCustomizer the customizers to add + */ + public void addContextCustomizers( + NettyServerCustomizer... nettyServerCustomizer) { + Assert.notNull(nettyServerCustomizer, + "NettyWebServerCustomizer must not be null"); + this.nettyServerCustomizers.addAll(Arrays.asList(nettyServerCustomizer)); + } + private HttpServer createHttpServer() { - HttpServer server; + return HttpServer.builder().options(options -> { + options.listenAddress(getListenAddress()); + this.nettyServerCustomizers.forEach(customizer -> customizer.customize(options)); + }).build(); + } + + private InetSocketAddress getListenAddress() { if (getAddress() != null) { - server = HttpServer.create(getAddress().getHostAddress(), getPort()); + return new InetSocketAddress(getAddress().getHostAddress(), getPort()); } else { - server = HttpServer.create(getPort()); + return new InetSocketAddress(getPort()); } - return server; } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java new file mode 100644 index 00000000000..c13f1702012 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.web.embedded.netty; + +import reactor.ipc.netty.http.server.HttpServerOptions; + +/** + * Callback interface that can be used to customize a Reactor Netty server builder. + * + * @author Brian Clozel + * @see NettyReactiveWebServerFactory + * @since 2.0.0 + */ +@FunctionalInterface +public interface NettyServerCustomizer { + + /** + * Customize the Netty web server. + * @param builder the server options builder to customize + */ + void customize(HttpServerOptions.Builder builder); +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index 077d78253a7..2eb54193e3d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -16,13 +16,20 @@ package org.springframework.boot.web.embedded.netty; +import java.util.Arrays; + import org.junit.Test; +import org.mockito.InOrder; +import reactor.ipc.netty.http.server.HttpServerOptions; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests; import org.springframework.boot.web.server.PortInUseException; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; /** * Tests for {@link NettyReactiveWebServerFactory}. @@ -33,7 +40,7 @@ public class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests { @Override - protected AbstractReactiveWebServerFactory getFactory() { + protected NettyReactiveWebServerFactory getFactory() { return new NettyReactiveWebServerFactory(0); } @@ -50,4 +57,20 @@ public class NettyReactiveWebServerFactoryTests factory.getWebServer(new EchoHandler()).start(); } + @Test + public void nettyCustomizers() throws Exception { + NettyReactiveWebServerFactory factory = getFactory(); + NettyServerCustomizer[] customizers = new NettyServerCustomizer[2]; + for (int i = 0; i < customizers.length; i++) { + customizers[i] = mock(NettyServerCustomizer.class); + } + factory.setNettyServerCustomizers(Arrays.asList(customizers[0], customizers[1])); + this.webServer = factory.getWebServer(new EchoHandler()); + + InOrder ordered = inOrder((Object[]) customizers); + for (NettyServerCustomizer customizer : customizers) { + ordered.verify(customizer).customize(any(HttpServerOptions.Builder.class)); + } + } + }