CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-starter-webflux

Starter for building WebFlux applications using Spring Framework's Reactive Web support

Pending
Overview
Eval results
Files

server-configuration.mddocs/

Server Configuration

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.

Server Factory Interfaces

ReactiveWebServerFactory

public interface ReactiveWebServerFactory {
    WebServer getWebServer(HttpHandler httpHandler);
}

public interface ConfigurableReactiveWebServerFactory extends ReactiveWebServerFactory {
    void setPort(int port);
    void setAddress(InetAddress address);
    void setErrorPages(Set<? extends ErrorPage> errorPages);
    void setSsl(Ssl ssl);
    void setSslStoreProvider(SslStoreProvider sslStoreProvider);
    void setHttp2(Http2 http2);
    void setCompression(Compression compression);
    void setServerHeader(String serverHeader);
    void setShutdown(Shutdown shutdown);
}

public abstract class AbstractReactiveWebServerFactory implements ConfigurableReactiveWebServerFactory {
    
    public void setPort(int port);
    public void setAddress(InetAddress address);
    public void setErrorPages(Set<? extends ErrorPage> errorPages);
    public void setSsl(Ssl ssl);
    public void setSslStoreProvider(SslStoreProvider sslStoreProvider);
    public void setHttp2(Http2 http2);
    public void setCompression(Compression compression);
    public void setServerHeader(String serverHeader);
    public void setShutdown(Shutdown shutdown);
    
    protected final void configureWebServer(WebServer webServer, ConfigurableWebServerFactory factory);
}

Embedded Server Implementations

Netty (Default)

public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory 
        implements ReactiveWebServerFactory, ResourceLoaderAware {
    
    public NettyReactiveWebServerFactory();
    public NettyReactiveWebServerFactory(int port);
    
    public void setResourceLoader(ResourceLoader resourceLoader);
    public void setUseForwardHeaders(boolean useForwardHeaders);
    public void addServerCustomizers(NettyServerCustomizer... customizers);
    public void setServerCustomizers(Collection<? extends NettyServerCustomizer> customizers);
    public Collection<NettyServerCustomizer> getServerCustomizers();
    
    @Override
    public WebServer getWebServer(HttpHandler httpHandler);
}

@FunctionalInterface
public interface NettyServerCustomizer {
    HttpServer apply(HttpServer server);
}

Tomcat

public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFactory 
        implements ResourceLoaderAware {
    
    public TomcatReactiveWebServerFactory();
    public TomcatReactiveWebServerFactory(int port);
    
    public void setResourceLoader(ResourceLoader resourceLoader);
    public void setBaseDirectory(File baseDirectory);
    public void setBackgroundProcessorDelay(int delay);
    public void addConnectorCustomizers(TomcatConnectorCustomizer... customizers);
    public void setConnectorCustomizers(Collection<? extends TomcatConnectorCustomizer> customizers);
    public void addContextCustomizers(TomcatContextCustomizer... customizers);
    public void setContextCustomizers(Collection<? extends TomcatContextCustomizer> customizers);
    public void addProtocolHandlerCustomizers(TomcatProtocolHandlerCustomizer<?>... customizers);
    public void setProtocolHandlerCustomizers(Collection<? extends TomcatProtocolHandlerCustomizer<?>> customizers);
    
    @Override
    public WebServer getWebServer(HttpHandler httpHandler);
}

Jetty

public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory 
        implements ResourceLoaderAware {
    
    public JettyReactiveWebServerFactory();
    public JettyReactiveWebServerFactory(int port);
    
    public void setResourceLoader(ResourceLoader resourceLoader);
    public void setUseForwardHeaders(boolean useForwardHeaders);
    public void setAcceptors(Integer acceptors);
    public void setSelectors(Integer selectors);
    public void addServerCustomizers(JettyServerCustomizer... customizers);
    public void setServerCustomizers(Collection<? extends JettyServerCustomizer> customizers);
    public void setThreadPool(ThreadPool threadPool);
    
    @Override
    public WebServer getWebServer(HttpHandler httpHandler);
}

@FunctionalInterface
public interface JettyServerCustomizer {
    void customize(Server server);
}

Undertow

public class UndertowReactiveWebServerFactory extends AbstractReactiveWebServerFactory 
        implements ResourceLoaderAware {
    
    public UndertowReactiveWebServerFactory();
    public UndertowReactiveWebServerFactory(int port);
    
    public void setResourceLoader(ResourceLoader resourceLoader);
    public void setBufferSize(Integer bufferSize);
    public void setIoThreads(Integer ioThreads);
    public void setWorkerThreads(Integer workerThreads);
    public void setDirectBuffers(Boolean directBuffers);
    public void setAccessLogEnabled(boolean accessLogEnabled);
    public void setAccessLogPattern(String accessLogPattern);
    public void setAccessLogPrefix(String accessLogPrefix);
    public void setAccessLogSuffix(String accessLogSuffix);
    public void setAccessLogDirectory(File accessLogDirectory);
    public void setAccessLogWriter(AccessLogWriter accessLogWriter);
    public void setUseForwardHeaders(boolean useForwardHeaders);
    public void addBuilderCustomizers(UndertowBuilderCustomizer... customizers);
    public void setBuilderCustomizers(Collection<? extends UndertowBuilderCustomizer> customizers);
    public void addDeploymentInfoCustomizers(UndertowDeploymentInfoCustomizer... customizers);
    public void setDeploymentInfoCustomizers(Collection<? extends UndertowDeploymentInfoCustomizer> customizers);
    
    @Override
    public WebServer getWebServer(HttpHandler httpHandler);
}

Configuration Properties

Server Properties

@ConfigurationProperties(prefix = "server")
public class ServerProperties {
    
    private Integer port;
    private InetAddress address;
    private final ErrorProperties error = new ErrorProperties();
    private final Ssl ssl = new Ssl();
    private final Compression compression = new Compression();
    private final Http2 http2 = new Http2();
    private String serverHeader;
    private Shutdown shutdown = Shutdown.IMMEDIATE;
    private final Netty netty = new Netty();
    private final Tomcat tomcat = new Tomcat();
    private final Jetty jetty = new Jetty();
    private final Undertow undertow = new Undertow();
    
    public static class Ssl {
        private boolean enabled = true;
        private String[] ciphers;
        private String[] enabledProtocols;
        private String keyAlias;
        private String keyPassword;
        private String keyStore;
        private String keyStorePassword;
        private String keyStoreType;
        private String keyStoreProvider;
        private String trustStore;
        private String trustStorePassword;
        private String trustStoreType;
        private String trustStoreProvider;
        private String protocol = "TLS";
        private ClientAuth clientAuth;
    }
    
    public static class Http2 {
        private boolean enabled = false;
    }
    
    public static class Compression {
        private boolean enabled = false;
        private String[] mimeTypes = new String[] { "text/html", "text/xml", "text/plain", 
            "text/css", "text/javascript", "application/javascript", "application/json", 
            "application/xml" };
        private String[] excludedUserAgents;
        private DataSize minResponseSize = DataSize.ofKilobytes(2);
    }
}

Netty Properties

public static class Netty {
    private Duration connectionTimeout;
    private final H2c h2c = new H2c();
    private Duration idleTimeout;
    private Integer maxKeepAliveRequests;
    
    public static class H2c {
        private boolean enabled = false;
    }
}

Tomcat Properties

public static class Tomcat {
    private Charset uriEncoding = StandardCharsets.UTF_8;
    private boolean redirectContextRoot = true;
    private boolean useRelativeRedirects;
    private int maxConnections = 8192;
    private int acceptCount = 100;
    private Duration processorCache = Duration.ofSeconds(200);
    private int maxHttpHeaderSize = DataSize.ofKilobytes(8).toBytes();
    private boolean rejectIllegalHeader = true;
    private final Accesslog accesslog = new Accesslog();
    private final Threads threads = new Threads();
    private final Resource resource = new Resource();
    private final Mbeanregistry mbeanregistry = new Mbeanregistry();
    
    public static class Accesslog {
        private boolean enabled = false;
        private boolean checkExists = false;
        private String pattern = "common";
        private String directory = "logs";
        private String prefix = "access_log";
        private String suffix = ".log";
        private String encoding;
        private String locale;
        private boolean requestAttributesEnabled = false;
        private boolean rotate = true;
        private boolean renameOnRotate = false;
        private int maxDays = -1;
        private String fileDateFormat = ".yyyy-MM-dd";
        private boolean ipv6Canonical = false;
    }
}

SSL Configuration

SSL Setup

@Configuration
public class SslConfiguration {
    
    @Bean
    public TomcatServletWebServerFactory tomcatFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addConnectorCustomizers(connector -> {
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setPort(8443);
            
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile("/path/to/keystore.p12");
            protocol.setKeystoreType("PKCS12");
            protocol.setKeystorePass("password");
            protocol.setKeyAlias("tomcat");
        });
        return factory;
    }
    
    @Bean
    public NettyReactiveWebServerFactory nettyFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        factory.addServerCustomizers(httpServer -> {
            SslContext sslContext = SslContextBuilder.forServer(certificateChainFile, privateKeyFile)
                .trustManager(InsecureTrustManagerFactory.INSTANCE)
                .build();
            return httpServer.secure(sslSpec -> sslSpec.sslContext(sslContext));
        });
        return factory;
    }
}

Programmatic SSL Configuration

@Configuration
public class ProgrammaticSslConfiguration {
    
    @Bean
    public ReactiveWebServerFactory webServerFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        
        Ssl ssl = new Ssl();
        ssl.setEnabled(true);
        ssl.setKeyStore("classpath:keystore.p12");
        ssl.setKeyStorePassword("password");
        ssl.setKeyStoreType("PKCS12");
        ssl.setKeyAlias("spring");
        ssl.setProtocol("TLS");
        ssl.setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
        
        factory.setSsl(ssl);
        factory.setPort(8443);
        
        return factory;
    }
}

Performance Tuning

Netty Performance Configuration

@Configuration
public class NettyPerformanceConfiguration {
    
    @Bean
    public NettyReactiveWebServerFactory nettyServerFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        
        factory.addServerCustomizers(httpServer -> {
            return httpServer
                .option(ChannelOption.SO_BACKLOG, 1024)
                .option(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_RCVBUF, 32 * 1024)
                .childOption(ChannelOption.SO_SNDBUF, 32 * 1024)
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, 
                    new WriteBufferWaterMark(8 * 1024, 32 * 1024))
                .handle((inbound, outbound) -> {
                    // Custom handler logic
                    return outbound.sendString(Mono.just("Hello World"));
                });
        });
        
        return factory;
    }
}

Connection Pool Configuration

@Configuration
public class ConnectionPoolConfiguration {
    
    @Bean
    public ConnectionProvider connectionProvider() {
        return ConnectionProvider.builder("custom")
            .maxConnections(100)
            .maxIdleTime(Duration.ofSeconds(20))
            .maxLifeTime(Duration.ofSeconds(60))
            .pendingAcquireTimeout(Duration.ofSeconds(60))
            .evictInBackground(Duration.ofSeconds(120))
            .build();
    }
    
    @Bean
    public ReactorResourceFactory resourceFactory() {
        ReactorResourceFactory factory = new ReactorResourceFactory();
        factory.setUseGlobalResources(false);
        factory.setConnectionProvider(connectionProvider());
        factory.setLoopResources(LoopResources.create("http-nio", 4, true));
        return factory;
    }
}

Server Customization Examples

Custom Error Pages

@Configuration
public class ErrorPageConfiguration {
    
    @Bean
    public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> webServerCustomizer() {
        return factory -> {
            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
            ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
            ErrorPage errorPage = new ErrorPage("/error");
            
            factory.setErrorPages(Set.of(error404Page, error500Page, errorPage));
        };
    }
}

Custom Port Configuration

@Configuration
public class MultiPortConfiguration {
    
    @Bean
    public NettyReactiveWebServerFactory httpServerFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        factory.setPort(8080);
        return factory;
    }
    
    @Bean
    public NettyReactiveWebServerFactory httpsServerFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        factory.setPort(8443);
        
        Ssl ssl = new Ssl();
        ssl.setEnabled(true);
        ssl.setKeyStore("classpath:keystore.p12");
        ssl.setKeyStorePassword("password");
        factory.setSsl(ssl);
        
        return factory;
    }
    
    @Bean
    public TomcatReactiveWebServerFactory additionalTomcatFactory() {
        TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
        factory.setPort(9090);
        factory.addConnectorCustomizers(connector -> {
            connector.setMaxPostSize(1024 * 1024); // 1MB
            connector.setMaxSavePostSize(1024 * 1024);
        });
        return factory;
    }
}

Compression Configuration

@Configuration
public class CompressionConfiguration {
    
    @Bean
    public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> compressionCustomizer() {
        return factory -> {
            Compression compression = new Compression();
            compression.setEnabled(true);
            compression.setMimeTypes(new String[]{
                "text/html", "text/xml", "text/plain", "text/css", "text/javascript",
                "application/javascript", "application/json", "application/xml"
            });
            compression.setMinResponseSize(DataSize.of(1024)); // 1KB minimum
            factory.setCompression(compression);
        };
    }
}

Logging and Monitoring

@Configuration
public class ServerMonitoringConfiguration {
    
    @Bean
    public NettyReactiveWebServerFactory monitoredNettyFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        
        factory.addServerCustomizers(httpServer -> {
            return httpServer
                .metrics(true, Function.identity()) // Enable metrics
                .doOnConnection(connection -> {
                    log.info("New connection established: {}", 
                        connection.channel().remoteAddress());
                    
                    connection.onDispose(() -> 
                        log.info("Connection closed: {}", 
                            connection.channel().remoteAddress()));
                })
                .accessLog(true) // Enable access logging
                .wiretap(true); // Enable wire-level logging
        });
        
        return factory;
    }
    
    @Bean
    public TomcatReactiveWebServerFactory monitoredTomcatFactory() {
        TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
        
        factory.addConnectorCustomizers(connector -> {
            connector.setAttribute("server.tomcat.accesslog.enabled", true);
            connector.setAttribute("server.tomcat.accesslog.pattern", 
                "%h %l %u %t \"%r\" %s %b %D");
        });
        
        return factory;
    }
}

Health and Graceful Shutdown

Graceful Shutdown Configuration

@Configuration
public class GracefulShutdownConfiguration {
    
    @Bean
    public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> gracefulShutdownCustomizer() {
        return factory -> {
            factory.setShutdown(Shutdown.GRACEFUL);
        };
    }
    
    @Bean
    public GracefulShutdown gracefulShutdown() {
        return new GracefulShutdown();
    }
    
    @EventListener
    public void handleContextClose(ContextClosedEvent event) {
        log.info("Application context is closing, initiating graceful shutdown");
    }
    
    @PreDestroy
    public void onDestroy() throws InterruptedException {
        log.info("Waiting for active requests to complete...");
        Thread.sleep(5000); // Wait 5 seconds for requests to complete
        log.info("Graceful shutdown completed");
    }
}

Health Check Endpoints

@RestController
public class HealthController {
    
    private final ReactiveHealthIndicator customHealthIndicator;
    
    public HealthController(ReactiveHealthIndicator customHealthIndicator) {
        this.customHealthIndicator = customHealthIndicator;
    }
    
    @GetMapping("/health")
    public Mono<ResponseEntity<Map<String, Object>>> health() {
        return customHealthIndicator.getHealth(true)
            .map(health -> {
                HttpStatus status = health.getStatus() == Status.UP ? 
                    HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE;
                return ResponseEntity.status(status).body(health.getDetails());
            });
    }
    
    @GetMapping("/readiness")
    public Mono<ResponseEntity<String>> readiness() {
        return Mono.fromCallable(() -> {
            // Check if application is ready to serve traffic
            boolean ready = checkDatabaseConnection() && checkExternalServices();
            return ready ? 
                ResponseEntity.ok("READY") : 
                ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("NOT_READY");
        });
    }
    
    @GetMapping("/liveness")
    public Mono<ResponseEntity<String>> liveness() {
        return Mono.just(ResponseEntity.ok("ALIVE"));
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-starter-webflux

docs

annotation-controllers.md

configuration.md

error-handling.md

functional-routing.md

index.md

server-configuration.md

testing.md

webclient.md

tile.json