or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-controllers.mdconfiguration.mderror-handling.mdfunctional-routing.mdindex.mdserver-configuration.mdtesting.mdwebclient.md

server-configuration.mddocs/

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

```