Skip to content

Commit 6094212

Browse files
committed
Defer accessing loop resources until web server start
Closes gh-37209
1 parent 0fc97e9 commit 6094212

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import reactor.netty.http.HttpProtocol;
2929
import reactor.netty.http.server.HttpServer;
30-
import reactor.netty.resources.LoopResources;
3130

3231
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
3332
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
@@ -78,7 +77,7 @@ public WebServer getWebServer(HttpHandler httpHandler) {
7877

7978
NettyWebServer createNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,
8079
Duration lifecycleTimeout, Shutdown shutdown) {
81-
return new NettyWebServer(httpServer, handlerAdapter, lifecycleTimeout, shutdown);
80+
return new NettyWebServer(httpServer, handlerAdapter, lifecycleTimeout, shutdown, this.resourceFactory);
8281
}
8382

8483
/**
@@ -158,15 +157,7 @@ public Shutdown getShutdown() {
158157
}
159158

160159
private HttpServer createHttpServer() {
161-
HttpServer server = HttpServer.create();
162-
if (this.resourceFactory != null) {
163-
LoopResources resources = this.resourceFactory.getLoopResources();
164-
Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
165-
server = server.runOn(resources).bindAddress(this::getListenAddress);
166-
}
167-
else {
168-
server = server.bindAddress(this::getListenAddress);
169-
}
160+
HttpServer server = HttpServer.create().bindAddress(this::getListenAddress);
170161
if (Ssl.isEnabled(getSsl())) {
171162
server = customizeSslConfiguration(server);
172163
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@
3535
import reactor.netty.http.server.HttpServerRequest;
3636
import reactor.netty.http.server.HttpServerResponse;
3737
import reactor.netty.http.server.HttpServerRoutes;
38+
import reactor.netty.resources.LoopResources;
3839

3940
import org.springframework.boot.web.server.GracefulShutdownCallback;
4041
import org.springframework.boot.web.server.GracefulShutdownResult;
4142
import org.springframework.boot.web.server.PortInUseException;
4243
import org.springframework.boot.web.server.Shutdown;
4344
import org.springframework.boot.web.server.WebServer;
4445
import org.springframework.boot.web.server.WebServerException;
46+
import org.springframework.http.client.reactive.ReactorResourceFactory;
4547
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
4648
import org.springframework.util.Assert;
4749

@@ -74,19 +76,48 @@ public class NettyWebServer implements WebServer {
7476

7577
private final GracefulShutdown gracefulShutdown;
7678

79+
private final ReactorResourceFactory resourceFactory;
80+
7781
private List<NettyRouteProvider> routeProviders = Collections.emptyList();
7882

7983
private volatile DisposableServer disposableServer;
8084

85+
/**
86+
* Creates a new {@code NettyWebServer} instance.
87+
* @param httpServer the HTTP server
88+
* @param handlerAdapter the handler adapter
89+
* @param lifecycleTimeout the lifecycle timeout, may be {@code null}
90+
* @param shutdown the shutdown, may be {@code null}
91+
* @deprecated since 3.2.0 for removal in 3.4.0 in favor of
92+
* {@link #NettyWebServer(HttpServer, ReactorHttpHandlerAdapter, Duration, Shutdown, ReactorResourceFactory)}
93+
*/
94+
@Deprecated(since = "3.2.0", forRemoval = true)
8195
public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, Duration lifecycleTimeout,
8296
Shutdown shutdown) {
97+
this(httpServer, handlerAdapter, lifecycleTimeout, shutdown, null);
98+
}
99+
100+
/**
101+
* Creates a new {@code NettyWebServer} instance.
102+
* @param httpServer the HTTP server
103+
* @param handlerAdapter the handler adapter
104+
* @param lifecycleTimeout the lifecycle timeout, may be {@code null}
105+
* @param shutdown the shutdown, may be {@code null}
106+
* @param resourceFactory the factory for the server's {@link LoopResources loop
107+
* resources}, may be {@code null}
108+
* @since 3.2.0
109+
* {@link #NettyWebServer(HttpServer, ReactorHttpHandlerAdapter, Duration, Shutdown, ReactorResourceFactory)}
110+
*/
111+
public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, Duration lifecycleTimeout,
112+
Shutdown shutdown, ReactorResourceFactory resourceFactory) {
83113
Assert.notNull(httpServer, "HttpServer must not be null");
84114
Assert.notNull(handlerAdapter, "HandlerAdapter must not be null");
85115
this.lifecycleTimeout = lifecycleTimeout;
86116
this.handler = handlerAdapter;
87117
this.httpServer = httpServer.channelGroup(new DefaultChannelGroup(new DefaultEventExecutor()));
88118
this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(() -> this.disposableServer)
89119
: null;
120+
this.resourceFactory = resourceFactory;
90121
}
91122

92123
public void setRouteProviders(List<NettyRouteProvider> routeProviders) {
@@ -143,6 +174,11 @@ DisposableServer startHttpServer() {
143174
else {
144175
server = server.route(this::applyRouteProviders);
145176
}
177+
if (this.resourceFactory != null) {
178+
LoopResources resources = this.resourceFactory.getLoopResources();
179+
Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
180+
server = server.runOn(resources);
181+
}
146182
if (this.lifecycleTimeout != null) {
147183
return server.bindNow(this.lifecycleTimeout);
148184
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@
4141
import org.springframework.boot.web.server.Ssl;
4242
import org.springframework.http.MediaType;
4343
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
44+
import org.springframework.http.client.reactive.ReactorResourceFactory;
4445
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
4546
import org.springframework.web.reactive.function.BodyInserters;
4647
import org.springframework.web.reactive.function.client.WebClient;
4748

4849
import static org.assertj.core.api.Assertions.assertThat;
4950
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
51+
import static org.assertj.core.api.Assertions.assertThatNoException;
5052
import static org.mockito.ArgumentMatchers.any;
5153
import static org.mockito.BDDMockito.given;
5254
import static org.mockito.Mockito.inOrder;
@@ -80,6 +82,23 @@ void getPortWhenDisposableServerPortOperationIsUnsupportedReturnsMinusOne() {
8082
assertThat(this.webServer.getPort()).isEqualTo(-1);
8183
}
8284

85+
@Test
86+
void resourceFactoryAndWebServerLifecycle() {
87+
NettyReactiveWebServerFactory factory = getFactory();
88+
factory.setPort(0);
89+
ReactorResourceFactory resourceFactory = new ReactorResourceFactory();
90+
factory.setResourceFactory(resourceFactory);
91+
this.webServer = factory.getWebServer(new EchoHandler());
92+
assertThatNoException().isThrownBy(() -> {
93+
resourceFactory.start();
94+
this.webServer.start();
95+
this.webServer.stop();
96+
resourceFactory.stop();
97+
resourceFactory.start();
98+
this.webServer.start();
99+
});
100+
}
101+
83102
private void portMatchesRequirement(PortInUseException exception) {
84103
assertThat(exception.getPort()).isEqualTo(this.webServer.getPort());
85104
}
@@ -199,7 +218,7 @@ static class NoPortNettyWebServer extends NettyWebServer {
199218

200219
NoPortNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, Duration lifecycleTimeout,
201220
Shutdown shutdown) {
202-
super(httpServer, handlerAdapter, lifecycleTimeout, shutdown);
221+
super(httpServer, handlerAdapter, lifecycleTimeout, shutdown, null);
203222
}
204223

205224
@Override

0 commit comments

Comments
 (0)