0
# Server Configuration
1
2
Spring Boot WebFlux provides comprehensive server configuration supporting multiple embedded servers (Netty, Tomcat, Jetty, Undertow) with extensive customization options for production deployments. The reactive server architecture enables high-concurrency applications with efficient resource utilization.
3
4
## Server Factory Interfaces
5
6
### ReactiveWebServerFactory
7
8
```java { .api }
9
public interface ReactiveWebServerFactory {
10
WebServer getWebServer(HttpHandler httpHandler);
11
}
12
13
public interface ConfigurableReactiveWebServerFactory extends ReactiveWebServerFactory {
14
void setPort(int port);
15
void setAddress(InetAddress address);
16
void setErrorPages(Set<? extends ErrorPage> errorPages);
17
void setSsl(Ssl ssl);
18
void setSslStoreProvider(SslStoreProvider sslStoreProvider);
19
void setHttp2(Http2 http2);
20
void setCompression(Compression compression);
21
void setServerHeader(String serverHeader);
22
void setShutdown(Shutdown shutdown);
23
}
24
25
public abstract class AbstractReactiveWebServerFactory implements ConfigurableReactiveWebServerFactory {
26
27
public void setPort(int port);
28
public void setAddress(InetAddress address);
29
public void setErrorPages(Set<? extends ErrorPage> errorPages);
30
public void setSsl(Ssl ssl);
31
public void setSslStoreProvider(SslStoreProvider sslStoreProvider);
32
public void setHttp2(Http2 http2);
33
public void setCompression(Compression compression);
34
public void setServerHeader(String serverHeader);
35
public void setShutdown(Shutdown shutdown);
36
37
protected final void configureWebServer(WebServer webServer, ConfigurableWebServerFactory factory);
38
}
39
```
40
41
## Embedded Server Implementations
42
43
### Netty (Default)
44
45
```java { .api }
46
public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory
47
implements ReactiveWebServerFactory, ResourceLoaderAware {
48
49
public NettyReactiveWebServerFactory();
50
public NettyReactiveWebServerFactory(int port);
51
52
public void setResourceLoader(ResourceLoader resourceLoader);
53
public void setUseForwardHeaders(boolean useForwardHeaders);
54
public void addServerCustomizers(NettyServerCustomizer... customizers);
55
public void setServerCustomizers(Collection<? extends NettyServerCustomizer> customizers);
56
public Collection<NettyServerCustomizer> getServerCustomizers();
57
58
@Override
59
public WebServer getWebServer(HttpHandler httpHandler);
60
}
61
62
@FunctionalInterface
63
public interface NettyServerCustomizer {
64
HttpServer apply(HttpServer server);
65
}
66
```
67
68
### Tomcat
69
70
```java { .api }
71
public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFactory
72
implements ResourceLoaderAware {
73
74
public TomcatReactiveWebServerFactory();
75
public TomcatReactiveWebServerFactory(int port);
76
77
public void setResourceLoader(ResourceLoader resourceLoader);
78
public void setBaseDirectory(File baseDirectory);
79
public void setBackgroundProcessorDelay(int delay);
80
public void addConnectorCustomizers(TomcatConnectorCustomizer... customizers);
81
public void setConnectorCustomizers(Collection<? extends TomcatConnectorCustomizer> customizers);
82
public void addContextCustomizers(TomcatContextCustomizer... customizers);
83
public void setContextCustomizers(Collection<? extends TomcatContextCustomizer> customizers);
84
public void addProtocolHandlerCustomizers(TomcatProtocolHandlerCustomizer<?>... customizers);
85
public void setProtocolHandlerCustomizers(Collection<? extends TomcatProtocolHandlerCustomizer<?>> customizers);
86
87
@Override
88
public WebServer getWebServer(HttpHandler httpHandler);
89
}
90
```
91
92
### Jetty
93
94
```java { .api }
95
public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory
96
implements ResourceLoaderAware {
97
98
public JettyReactiveWebServerFactory();
99
public JettyReactiveWebServerFactory(int port);
100
101
public void setResourceLoader(ResourceLoader resourceLoader);
102
public void setUseForwardHeaders(boolean useForwardHeaders);
103
public void setAcceptors(Integer acceptors);
104
public void setSelectors(Integer selectors);
105
public void addServerCustomizers(JettyServerCustomizer... customizers);
106
public void setServerCustomizers(Collection<? extends JettyServerCustomizer> customizers);
107
public void setThreadPool(ThreadPool threadPool);
108
109
@Override
110
public WebServer getWebServer(HttpHandler httpHandler);
111
}
112
113
@FunctionalInterface
114
public interface JettyServerCustomizer {
115
void customize(Server server);
116
}
117
```
118
119
### Undertow
120
121
```java { .api }
122
public class UndertowReactiveWebServerFactory extends AbstractReactiveWebServerFactory
123
implements ResourceLoaderAware {
124
125
public UndertowReactiveWebServerFactory();
126
public UndertowReactiveWebServerFactory(int port);
127
128
public void setResourceLoader(ResourceLoader resourceLoader);
129
public void setBufferSize(Integer bufferSize);
130
public void setIoThreads(Integer ioThreads);
131
public void setWorkerThreads(Integer workerThreads);
132
public void setDirectBuffers(Boolean directBuffers);
133
public void setAccessLogEnabled(boolean accessLogEnabled);
134
public void setAccessLogPattern(String accessLogPattern);
135
public void setAccessLogPrefix(String accessLogPrefix);
136
public void setAccessLogSuffix(String accessLogSuffix);
137
public void setAccessLogDirectory(File accessLogDirectory);
138
public void setAccessLogWriter(AccessLogWriter accessLogWriter);
139
public void setUseForwardHeaders(boolean useForwardHeaders);
140
public void addBuilderCustomizers(UndertowBuilderCustomizer... customizers);
141
public void setBuilderCustomizers(Collection<? extends UndertowBuilderCustomizer> customizers);
142
public void addDeploymentInfoCustomizers(UndertowDeploymentInfoCustomizer... customizers);
143
public void setDeploymentInfoCustomizers(Collection<? extends UndertowDeploymentInfoCustomizer> customizers);
144
145
@Override
146
public WebServer getWebServer(HttpHandler httpHandler);
147
}
148
```
149
150
## Configuration Properties
151
152
### Server Properties
153
154
```java { .api }
155
@ConfigurationProperties(prefix = "server")
156
public class ServerProperties {
157
158
private Integer port;
159
private InetAddress address;
160
private final ErrorProperties error = new ErrorProperties();
161
private final Ssl ssl = new Ssl();
162
private final Compression compression = new Compression();
163
private final Http2 http2 = new Http2();
164
private String serverHeader;
165
private Shutdown shutdown = Shutdown.IMMEDIATE;
166
private final Netty netty = new Netty();
167
private final Tomcat tomcat = new Tomcat();
168
private final Jetty jetty = new Jetty();
169
private final Undertow undertow = new Undertow();
170
171
public static class Ssl {
172
private boolean enabled = true;
173
private String[] ciphers;
174
private String[] enabledProtocols;
175
private String keyAlias;
176
private String keyPassword;
177
private String keyStore;
178
private String keyStorePassword;
179
private String keyStoreType;
180
private String keyStoreProvider;
181
private String trustStore;
182
private String trustStorePassword;
183
private String trustStoreType;
184
private String trustStoreProvider;
185
private String protocol = "TLS";
186
private ClientAuth clientAuth;
187
}
188
189
public static class Http2 {
190
private boolean enabled = false;
191
}
192
193
public static class Compression {
194
private boolean enabled = false;
195
private String[] mimeTypes = new String[] { "text/html", "text/xml", "text/plain",
196
"text/css", "text/javascript", "application/javascript", "application/json",
197
"application/xml" };
198
private String[] excludedUserAgents;
199
private DataSize minResponseSize = DataSize.ofKilobytes(2);
200
}
201
}
202
```
203
204
### Netty Properties
205
206
```java { .api }
207
public static class Netty {
208
private Duration connectionTimeout;
209
private final H2c h2c = new H2c();
210
private Duration idleTimeout;
211
private Integer maxKeepAliveRequests;
212
213
public static class H2c {
214
private boolean enabled = false;
215
}
216
}
217
```
218
219
### Tomcat Properties
220
221
```java { .api }
222
public static class Tomcat {
223
private Charset uriEncoding = StandardCharsets.UTF_8;
224
private boolean redirectContextRoot = true;
225
private boolean useRelativeRedirects;
226
private int maxConnections = 8192;
227
private int acceptCount = 100;
228
private Duration processorCache = Duration.ofSeconds(200);
229
private int maxHttpHeaderSize = DataSize.ofKilobytes(8).toBytes();
230
private boolean rejectIllegalHeader = true;
231
private final Accesslog accesslog = new Accesslog();
232
private final Threads threads = new Threads();
233
private final Resource resource = new Resource();
234
private final Mbeanregistry mbeanregistry = new Mbeanregistry();
235
236
public static class Accesslog {
237
private boolean enabled = false;
238
private boolean checkExists = false;
239
private String pattern = "common";
240
private String directory = "logs";
241
private String prefix = "access_log";
242
private String suffix = ".log";
243
private String encoding;
244
private String locale;
245
private boolean requestAttributesEnabled = false;
246
private boolean rotate = true;
247
private boolean renameOnRotate = false;
248
private int maxDays = -1;
249
private String fileDateFormat = ".yyyy-MM-dd";
250
private boolean ipv6Canonical = false;
251
}
252
}
253
```
254
255
## SSL Configuration
256
257
### SSL Setup
258
259
```java
260
@Configuration
261
public class SslConfiguration {
262
263
@Bean
264
public TomcatServletWebServerFactory tomcatFactory() {
265
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
266
factory.addConnectorCustomizers(connector -> {
267
connector.setScheme("https");
268
connector.setSecure(true);
269
connector.setPort(8443);
270
271
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
272
protocol.setSSLEnabled(true);
273
protocol.setKeystoreFile("/path/to/keystore.p12");
274
protocol.setKeystoreType("PKCS12");
275
protocol.setKeystorePass("password");
276
protocol.setKeyAlias("tomcat");
277
});
278
return factory;
279
}
280
281
@Bean
282
public NettyReactiveWebServerFactory nettyFactory() {
283
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
284
factory.addServerCustomizers(httpServer -> {
285
SslContext sslContext = SslContextBuilder.forServer(certificateChainFile, privateKeyFile)
286
.trustManager(InsecureTrustManagerFactory.INSTANCE)
287
.build();
288
return httpServer.secure(sslSpec -> sslSpec.sslContext(sslContext));
289
});
290
return factory;
291
}
292
}
293
```
294
295
### Programmatic SSL Configuration
296
297
```java
298
@Configuration
299
public class ProgrammaticSslConfiguration {
300
301
@Bean
302
public ReactiveWebServerFactory webServerFactory() {
303
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
304
305
Ssl ssl = new Ssl();
306
ssl.setEnabled(true);
307
ssl.setKeyStore("classpath:keystore.p12");
308
ssl.setKeyStorePassword("password");
309
ssl.setKeyStoreType("PKCS12");
310
ssl.setKeyAlias("spring");
311
ssl.setProtocol("TLS");
312
ssl.setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
313
314
factory.setSsl(ssl);
315
factory.setPort(8443);
316
317
return factory;
318
}
319
}
320
```
321
322
## Performance Tuning
323
324
### Netty Performance Configuration
325
326
```java
327
@Configuration
328
public class NettyPerformanceConfiguration {
329
330
@Bean
331
public NettyReactiveWebServerFactory nettyServerFactory() {
332
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
333
334
factory.addServerCustomizers(httpServer -> {
335
return httpServer
336
.option(ChannelOption.SO_BACKLOG, 1024)
337
.option(ChannelOption.SO_REUSEADDR, true)
338
.childOption(ChannelOption.SO_KEEPALIVE, true)
339
.childOption(ChannelOption.TCP_NODELAY, true)
340
.childOption(ChannelOption.SO_RCVBUF, 32 * 1024)
341
.childOption(ChannelOption.SO_SNDBUF, 32 * 1024)
342
.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
343
new WriteBufferWaterMark(8 * 1024, 32 * 1024))
344
.handle((inbound, outbound) -> {
345
// Custom handler logic
346
return outbound.sendString(Mono.just("Hello World"));
347
});
348
});
349
350
return factory;
351
}
352
}
353
```
354
355
### Connection Pool Configuration
356
357
```java
358
@Configuration
359
public class ConnectionPoolConfiguration {
360
361
@Bean
362
public ConnectionProvider connectionProvider() {
363
return ConnectionProvider.builder("custom")
364
.maxConnections(100)
365
.maxIdleTime(Duration.ofSeconds(20))
366
.maxLifeTime(Duration.ofSeconds(60))
367
.pendingAcquireTimeout(Duration.ofSeconds(60))
368
.evictInBackground(Duration.ofSeconds(120))
369
.build();
370
}
371
372
@Bean
373
public ReactorResourceFactory resourceFactory() {
374
ReactorResourceFactory factory = new ReactorResourceFactory();
375
factory.setUseGlobalResources(false);
376
factory.setConnectionProvider(connectionProvider());
377
factory.setLoopResources(LoopResources.create("http-nio", 4, true));
378
return factory;
379
}
380
}
381
```
382
383
## Server Customization Examples
384
385
### Custom Error Pages
386
387
```java
388
@Configuration
389
public class ErrorPageConfiguration {
390
391
@Bean
392
public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> webServerCustomizer() {
393
return factory -> {
394
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
395
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
396
ErrorPage errorPage = new ErrorPage("/error");
397
398
factory.setErrorPages(Set.of(error404Page, error500Page, errorPage));
399
};
400
}
401
}
402
```
403
404
### Custom Port Configuration
405
406
```java
407
@Configuration
408
public class MultiPortConfiguration {
409
410
@Bean
411
public NettyReactiveWebServerFactory httpServerFactory() {
412
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
413
factory.setPort(8080);
414
return factory;
415
}
416
417
@Bean
418
public NettyReactiveWebServerFactory httpsServerFactory() {
419
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
420
factory.setPort(8443);
421
422
Ssl ssl = new Ssl();
423
ssl.setEnabled(true);
424
ssl.setKeyStore("classpath:keystore.p12");
425
ssl.setKeyStorePassword("password");
426
factory.setSsl(ssl);
427
428
return factory;
429
}
430
431
@Bean
432
public TomcatReactiveWebServerFactory additionalTomcatFactory() {
433
TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
434
factory.setPort(9090);
435
factory.addConnectorCustomizers(connector -> {
436
connector.setMaxPostSize(1024 * 1024); // 1MB
437
connector.setMaxSavePostSize(1024 * 1024);
438
});
439
return factory;
440
}
441
}
442
```
443
444
### Compression Configuration
445
446
```java
447
@Configuration
448
public class CompressionConfiguration {
449
450
@Bean
451
public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> compressionCustomizer() {
452
return factory -> {
453
Compression compression = new Compression();
454
compression.setEnabled(true);
455
compression.setMimeTypes(new String[]{
456
"text/html", "text/xml", "text/plain", "text/css", "text/javascript",
457
"application/javascript", "application/json", "application/xml"
458
});
459
compression.setMinResponseSize(DataSize.of(1024)); // 1KB minimum
460
factory.setCompression(compression);
461
};
462
}
463
}
464
```
465
466
### Logging and Monitoring
467
468
```java
469
@Configuration
470
public class ServerMonitoringConfiguration {
471
472
@Bean
473
public NettyReactiveWebServerFactory monitoredNettyFactory() {
474
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
475
476
factory.addServerCustomizers(httpServer -> {
477
return httpServer
478
.metrics(true, Function.identity()) // Enable metrics
479
.doOnConnection(connection -> {
480
log.info("New connection established: {}",
481
connection.channel().remoteAddress());
482
483
connection.onDispose(() ->
484
log.info("Connection closed: {}",
485
connection.channel().remoteAddress()));
486
})
487
.accessLog(true) // Enable access logging
488
.wiretap(true); // Enable wire-level logging
489
});
490
491
return factory;
492
}
493
494
@Bean
495
public TomcatReactiveWebServerFactory monitoredTomcatFactory() {
496
TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
497
498
factory.addConnectorCustomizers(connector -> {
499
connector.setAttribute("server.tomcat.accesslog.enabled", true);
500
connector.setAttribute("server.tomcat.accesslog.pattern",
501
"%h %l %u %t \"%r\" %s %b %D");
502
});
503
504
return factory;
505
}
506
}
507
```
508
509
## Health and Graceful Shutdown
510
511
### Graceful Shutdown Configuration
512
513
```java
514
@Configuration
515
public class GracefulShutdownConfiguration {
516
517
@Bean
518
public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> gracefulShutdownCustomizer() {
519
return factory -> {
520
factory.setShutdown(Shutdown.GRACEFUL);
521
};
522
}
523
524
@Bean
525
public GracefulShutdown gracefulShutdown() {
526
return new GracefulShutdown();
527
}
528
529
@EventListener
530
public void handleContextClose(ContextClosedEvent event) {
531
log.info("Application context is closing, initiating graceful shutdown");
532
}
533
534
@PreDestroy
535
public void onDestroy() throws InterruptedException {
536
log.info("Waiting for active requests to complete...");
537
Thread.sleep(5000); // Wait 5 seconds for requests to complete
538
log.info("Graceful shutdown completed");
539
}
540
}
541
```
542
543
### Health Check Endpoints
544
545
```java
546
@RestController
547
public class HealthController {
548
549
private final ReactiveHealthIndicator customHealthIndicator;
550
551
public HealthController(ReactiveHealthIndicator customHealthIndicator) {
552
this.customHealthIndicator = customHealthIndicator;
553
}
554
555
@GetMapping("/health")
556
public Mono<ResponseEntity<Map<String, Object>>> health() {
557
return customHealthIndicator.getHealth(true)
558
.map(health -> {
559
HttpStatus status = health.getStatus() == Status.UP ?
560
HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE;
561
return ResponseEntity.status(status).body(health.getDetails());
562
});
563
}
564
565
@GetMapping("/readiness")
566
public Mono<ResponseEntity<String>> readiness() {
567
return Mono.fromCallable(() -> {
568
// Check if application is ready to serve traffic
569
boolean ready = checkDatabaseConnection() && checkExternalServices();
570
return ready ?
571
ResponseEntity.ok("READY") :
572
ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("NOT_READY");
573
});
574
}
575
576
@GetMapping("/liveness")
577
public Mono<ResponseEntity<String>> liveness() {
578
return Mono.just(ResponseEntity.ok("ALIVE"));
579
}
580
}
581
```