or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin-jmx.mdansi-support.mdaot-native-image.mdapplication-info.mdavailability.mdbootstrap.mdbootstrapping.mdbuilder.mdcloud-platform.mdconfiguration-annotations.mdconfiguration-data.mdconfiguration-properties.mdconversion.mddiagnostics.mdenvironment-property-sources.mdindex.mdjson-support.mdlifecycle-events.mdlogging.mdorigin-tracking.mdresource-loading.mdretry-support.mdssl-tls.mdstartup-metrics.mdsupport.mdsystem-utilities.mdtask-execution.mdthreading.mdutilities.mdvalidation.mdweb-support.md
tile.json

web-support.mddocs/

Spring Boot Web Application Support

Quick Reference

This documentation has been enhanced for AI coding agents with comprehensive examples, complete API signatures, thread safety notes, error handling patterns, and production-ready usage patterns.

Servlet Registration Components

ComponentPurposeThread SafetyKey Features
ServletRegistrationBeanRegister servletsThread-safe (Spring managed)URL mappings, init params, load-on-startup
FilterRegistrationBeanRegister filtersThread-safe (Spring managed)URL patterns, servlet names, dispatcher types
ServletListenerRegistrationBeanRegister listenersThread-safe (Spring managed)Servlet context, session, request listeners
DelegatingFilterProxyRegistrationBeanProxy Spring filtersThread-safeLazy initialization, Spring Security integration
ServletContextInitializerContext initializationN/A (functional interface)Programmatic servlet context configuration

Web Application Contexts

Context TypePurposeThread SafetyApplication Type
AnnotationConfigServletWebApplicationContextServlet web appsThread-safeTraditional servlet-based
AnnotationConfigReactiveWebApplicationContextReactive web appsThread-safeWebFlux reactive
GenericReactiveWebApplicationContextGeneric reactiveThread-safeReactive with manual configuration
ServletWebServerApplicationContextEmbedded servlet serverThread-safeSpring Boot servlet apps
ReactiveWebServerApplicationContextEmbedded reactive serverThread-safeSpring Boot reactive apps

Web Server Factories

FactoryPurposeThread SafetySupported Servers
ServletWebServerFactoryCreate servlet serversThread-safeTomcat, Jetty, Undertow
ReactiveWebServerFactoryCreate reactive serversThread-safeNetty, Tomcat, Jetty, Undertow
TomcatServletWebServerFactoryTomcat servlet serverThread-safeTomcat-specific
TomcatReactiveWebServerFactoryTomcat reactive serverThread-safeTomcat with WebFlux
JettyServletWebServerFactoryJetty servlet serverThread-safeJetty-specific
JettyReactiveWebServerFactoryJetty reactive serverThread-safeJetty with WebFlux
UndertowServletWebServerFactoryUndertow servlet serverThread-safeUndertow-specific
UndertowReactiveWebServerFactoryUndertow reactive serverThread-safeUndertow with WebFlux

Error Handling Components

ComponentPurposeThread SafetyUse Cases
ErrorPageError page definitionThread-safe (immutable)Status-based, exception-based routing
ErrorPageRegistryError page registrationThread-safeCustom error page configuration
ErrorPageRegistrarBulk error registrationN/A (callback)Register multiple error pages
ErrorPageFilterNon-embedded error handlingThread-safeWAR deployments without embedded server
ErrorAttributeOptionsError attribute controlThread-safe (immutable)Include/exclude stack traces, messages, etc.

Graceful Shutdown Support

ComponentPurposeThread SafetyBehavior
GracefulShutdownCallbackShutdown notificationThread-safeAsync shutdown completion notification
GracefulShutdownResultShutdown resultThread-safe (enum)SUCCESS, REQUESTS_ACTIVE, IDLE
ShutdownShutdown modeThread-safe (enum)IMMEDIATE, GRACEFUL

This document provides comprehensive coverage of Spring Boot's web application support for both servlet-based and reactive applications, including servlet registration, context management, error handling, and reactive web support.

Table of Contents

  1. Servlet Support
  2. Servlet Context Support
  3. Reactive Support
  4. Error Page Support
  5. Web Server Factory and Customization
  6. Web Server Context and Events

Servlet Support

Spring Boot provides a comprehensive set of classes for programmatically registering servlets, filters, and listeners in a Servlet 3.0+ environment.

ServletContextInitializer

The foundational interface for servlet context initialization.

package org.springframework.boot.web.servlet;

/**
 * Interface used to configure a Servlet 3.0+ ServletContext programmatically.
 * Unlike WebApplicationInitializer, classes that implement this interface
 * will not be automatically bootstrapped by the servlet container.
 *
 * This interface is designed to have a lifecycle managed by Spring, not the
 * servlet container.
 *
 * @since 4.0.0
 */
@FunctionalInterface
public interface ServletContextInitializer {

    /**
     * Configure the given ServletContext with any servlets, filters, listeners
     * context-params and attributes necessary for initialization.
     *
     * @param servletContext the ServletContext to initialize
     * @throws ServletException if any call against the given ServletContext
     *                          throws a ServletException
     */
    void onStartup(ServletContext servletContext) throws ServletException;
}

Usage Example:

@Configuration
public class WebConfig {

    @Bean
    public ServletContextInitializer customInitializer() {
        return servletContext -> {
            servletContext.setSessionTimeout(30);
            servletContext.setRequestCharacterEncoding("UTF-8");
        };
    }
}

ServletContextInitializerBeans

A collection of ServletContextInitializer instances obtained from a ListableBeanFactory. This class automatically discovers and adapts servlet components (servlets, filters, and listeners) as well as explicit ServletContextInitializer beans, sorting them appropriately for initialization.

Thread Safety: Instances are immutable after construction and thread-safe for iteration.

package org.springframework.boot.web.servlet;

import java.util.AbstractCollection;
import java.util.Iterator;
import org.springframework.beans.factory.ListableBeanFactory;

/**
 * A collection of ServletContextInitializers obtained from a ListableBeanFactory.
 * Includes all ServletContextInitializer beans and also adapts Servlet, Filter
 * and certain EventListener beans.
 *
 * Items are sorted so that adapted beans are top (Servlet, Filter then EventListener)
 * and direct ServletContextInitializer beans are at the end. Further sorting is
 * applied within these groups using the AnnotationAwareOrderComparator.
 *
 * @since 1.4.0
 */
public class ServletContextInitializerBeans
        extends AbstractCollection<ServletContextInitializer> {

    /**
     * Create a new ServletContextInitializerBeans instance.
     * Discovers and adapts all relevant beans from the given bean factory.
     *
     * @param beanFactory the bean factory to search
     * @param initializerTypes the initializer types to include (defaults to
     *                         ServletContextInitializer.class if not specified)
     */
    @SafeVarargs
    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
            Class<? extends ServletContextInitializer>... initializerTypes) {
        // Implementation scans bean factory and creates sorted collection
    }

    /**
     * Returns an iterator over the ServletContextInitializers in sorted order.
     *
     * Iteration Order:
     * 1. Servlet beans (adapted to ServletRegistrationBean)
     * 2. Filter beans (adapted to FilterRegistrationBean)
     * 3. EventListener beans (adapted to ServletListenerRegistrationBean)
     * 4. Direct ServletContextInitializer beans
     *
     * Within each group, beans are sorted by @Order annotation or Ordered interface.
     *
     * @return an iterator over ServletContextInitializers
     */
    @Override
    public Iterator<ServletContextInitializer> iterator() {
        // Returns iterator over sorted list
    }

    /**
     * Returns the number of ServletContextInitializers in the collection.
     *
     * @return the total count of initializers
     */
    @Override
    public int size() {
        // Returns size of sorted list
    }
}

Automatic Bean Discovery and Adaptation:

ServletContextInitializerBeans automatically discovers and adapts the following bean types:

  1. Servlet Beans - Automatically wrapped in ServletRegistrationBean

    • Default URL mapping: /{beanName}/ or / for dispatcherServlet
    • Supports @ServletRegistration annotation for configuration
    • Multipart configuration applied if available
  2. Filter Beans - Automatically wrapped in FilterRegistrationBean

    • Default mapping: applies to all URLs
    • Supports @FilterRegistration annotation for configuration
    • Dispatcher types, URL patterns, servlet names configurable
  3. EventListener Beans - Automatically wrapped in ServletListenerRegistrationBean

    • Supports servlet context listeners, session listeners, request listeners
    • Only supported listener types are included
  4. ServletContextInitializer Beans - Used directly

    • Includes all subtypes: ServletRegistrationBean, FilterRegistrationBean, etc.
    • No adaptation needed

Initialization Order:

The collection sorts initializers to ensure proper initialization sequence:

Priority 1 (Highest): Servlet beans (adapted)
Priority 2: Filter beans (adapted)
Priority 3: EventListener beans (adapted)
Priority 4 (Lowest): Direct ServletContextInitializer beans

Within each priority level, beans are further sorted by:

  • @Order annotation value
  • Ordered interface implementation
  • Default to Ordered.LOWEST_PRECEDENCE if not specified

Usage Example:

import org.springframework.boot.web.servlet.ServletContextInitializerBeans;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;

@Component
public class ServletInitializerManager {

    private final ServletContextInitializerBeans initializerBeans;

    public ServletInitializerManager(ApplicationContext applicationContext) {
        // Discover all ServletContextInitializer-related beans
        this.initializerBeans = new ServletContextInitializerBeans(
            applicationContext.getBeanFactory()
        );
    }

    public void initializeServletContext(ServletContext servletContext)
            throws ServletException {
        // Initialize servlet context with all discovered beans in sorted order
        for (ServletContextInitializer initializer : initializerBeans) {
            initializer.onStartup(servletContext);
        }
    }

    public int getInitializerCount() {
        return initializerBeans.size();
    }
}

Automatic Servlet Registration Example:

import jakarta.servlet.Servlet;
import jakarta.servlet.http.HttpServlet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
public class ServletConfig {

    /**
     * This servlet bean is automatically discovered and registered.
     * No explicit ServletRegistrationBean needed.
     */
    @Bean
    @Order(1)
    public Servlet myServlet() {
        return new HttpServlet() {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                    throws IOException {
                resp.getWriter().write("Hello from auto-registered servlet!");
            }
        };
    }

    /**
     * This servlet uses annotation-based configuration.
     */
    @Bean
    @ServletRegistration(
        name = "customServlet",
        urlMappings = {"/custom/*", "/api/*"},
        loadOnStartup = 1
    )
    @Order(1)
    public Servlet annotatedServlet() {
        return new CustomServlet();
    }
}

The myServlet bean above will be automatically:

  1. Discovered by ServletContextInitializerBeans
  2. Wrapped in a ServletRegistrationBean
  3. Registered with URL mapping /myServlet/
  4. Initialized during servlet context startup

Filter Auto-Registration Example:

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
public class FilterConfig {

    /**
     * Filter bean automatically registered to all URLs.
     */
    @Bean
    @Order(1)
    public Filter loggingFilter() {
        return (request, response, chain) -> {
            System.out.println("Request: " + request);
            chain.doFilter(request, response);
            System.out.println("Response: " + response);
        };
    }

    /**
     * Filter with annotation-based configuration.
     */
    @Bean
    @FilterRegistration(
        urlPatterns = {"/api/*"},
        servletNames = {"dispatcherServlet"},
        dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
    )
    @Order(10)
    public Filter apiFilter() {
        return new ApiSecurityFilter();
    }
}

Listener Auto-Registration Example:

import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletContextEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ListenerConfig {

    /**
     * Listener bean automatically registered.
     */
    @Bean
    public ServletContextListener contextListener() {
        return new ServletContextListener() {
            @Override
            public void contextInitialized(ServletContextEvent sce) {
                System.out.println("Servlet context initialized");
            }

            @Override
            public void contextDestroyed(ServletContextEvent sce) {
                System.out.println("Servlet context destroyed");
            }
        };
    }
}

Filtering by Initializer Type:

import org.springframework.boot.web.servlet.ServletContextInitializerBeans;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;

// Only discover ServletRegistrationBean and FilterRegistrationBean
ServletContextInitializerBeans beans = new ServletContextInitializerBeans(
    beanFactory,
    ServletRegistrationBean.class,
    FilterRegistrationBean.class
);

// Listeners and other initializer types are excluded

Best Practices:

  1. Use @Order for Control - Specify initialization order explicitly

    @Bean
    @Order(1)  // Lower numbers initialize first
    public Filter firstFilter() { ... }
    
    @Bean
    @Order(10)
    public Filter secondFilter() { ... }
  2. Prefer Bean Registration - Let Spring Boot auto-register simple components

    // GOOD: Simple bean registration
    @Bean
    public Filter myFilter() {
        return new MyFilter();
    }
    
    // AVOID: Manual registration unless customization needed
    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistration() {
        FilterRegistrationBean<MyFilter> registration =
            new FilterRegistrationBean<>(new MyFilter());
        registration.setUrlPatterns(List.of("/*"));
        return registration;
    }
  3. Use Annotations for Configuration - Apply @ServletRegistration or @FilterRegistration

    @Bean
    @ServletRegistration(
        urlMappings = {"/api/*"},
        loadOnStartup = 1
    )
    @Order(1)
    public Servlet apiServlet() {
        return new ApiServlet();
    }
  4. Explicit Registration for Complex Cases - Use registration beans when needed

    @Bean
    public FilterRegistrationBean<MyFilter> complexFilterRegistration() {
        FilterRegistrationBean<MyFilter> registration =
            new FilterRegistrationBean<>(new MyFilter());
        registration.setUrlPatterns(List.of("/secure/*", "/admin/*"));
        registration.setDispatcherTypes(
            DispatcherType.REQUEST,
            DispatcherType.FORWARD,
            DispatcherType.ERROR
        );
        registration.setMatchAfter(false);
        registration.setOrder(5);
        return registration;
    }

Thread Safety:

  • The ServletContextInitializerBeans collection is immutable after construction
  • Safe to iterate from multiple threads
  • Bean discovery happens once during construction
  • The sorted list is created once and never modified

Common Use Cases:

  1. Embedded Servlet Container Startup - Spring Boot uses this class internally to initialize the embedded servlet container with all discovered components

  2. Testing - Verify correct servlet/filter/listener registration order

  3. Custom Initialization Logic - Extend or wrap the initialization process

  4. Diagnostic Tools - Inspect what components will be registered

Integration with Spring Boot:

Spring Boot's embedded servlet container support (Tomcat, Jetty, Undertow) automatically uses ServletContextInitializerBeans to:

  1. Discover all servlet-related beans
  2. Adapt simple servlet/filter/listener beans to registration beans
  3. Sort all initializers by priority
  4. Apply them to the servlet context during startup

This provides a seamless bridge between Spring's bean management and the Servlet API initialization process.

ServletRegistrationBean

A ServletContextInitializer to register servlets in a Servlet 3.0+ container.

package org.springframework.boot.web.servlet;

/**
 * A ServletContextInitializer to register Servlets in a Servlet 3.0+ container.
 * Similar to ServletContext.addServlet() but with a Spring Bean friendly design.
 *
 * The servlet must be specified before calling onStartup. URL mapping can be
 * configured using setUrlMappings or omitted when mapping to '/*'.
 *
 * @param <T> the type of the Servlet to register
 * @since 1.4.0
 */
public class ServletRegistrationBean<T extends Servlet>
        extends DynamicRegistrationBean<ServletRegistration.Dynamic> {

    /**
     * Create a new ServletRegistrationBean instance.
     */
    public ServletRegistrationBean() { }

    /**
     * Create a new ServletRegistrationBean instance with the specified
     * Servlet and URL mappings.
     *
     * @param servlet the servlet being mapped
     * @param urlMappings the URLs being mapped
     */
    public ServletRegistrationBean(T servlet, String... urlMappings) { }

    /**
     * Create a new ServletRegistrationBean instance with the specified
     * Servlet and URL mappings.
     *
     * @param servlet the servlet being mapped
     * @param alwaysMapUrl if omitted URL mappings should be replaced with '/*'
     * @param urlMappings the URLs being mapped
     */
    public ServletRegistrationBean(T servlet, boolean alwaysMapUrl,
                                  String... urlMappings) { }

    /**
     * Sets the servlet to be registered.
     *
     * @param servlet the servlet
     */
    public void setServlet(T servlet) { }

    /**
     * Return the servlet being registered.
     *
     * @return the servlet
     */
    public T getServlet() { }

    /**
     * Set the URL mappings for the servlet. If not specified, the mapping
     * will default to '/'.
     *
     * @param urlMappings the mappings to set
     */
    public void setUrlMappings(Collection<String> urlMappings) { }

    /**
     * Return a mutable collection of the URL mappings for the servlet.
     *
     * @return the urlMappings
     */
    public Collection<String> getUrlMappings() { }

    /**
     * Add URL mappings for the servlet.
     *
     * @param urlMappings the mappings to add
     */
    public void addUrlMappings(String... urlMappings) { }

    /**
     * Sets the loadOnStartup priority.
     *
     * @param loadOnStartup if load on startup is enabled
     */
    public void setLoadOnStartup(int loadOnStartup) { }

    /**
     * Set the multi-part configuration.
     *
     * @param multipartConfig the multipart configuration to set or null
     */
    public void setMultipartConfig(MultipartConfigElement multipartConfig) { }

    /**
     * Returns the multi-part configuration to be applied or null.
     *
     * @return the multipart config
     */
    public MultipartConfigElement getMultipartConfig() { }

    /**
     * Returns the servlet name that will be registered.
     *
     * @return the servlet name
     */
    public String getServletName() { }
}

Usage Example:

@Configuration
public class ServletConfig {

    @Bean
    public ServletRegistrationBean<MyServlet> myServlet() {
        ServletRegistrationBean<MyServlet> bean =
            new ServletRegistrationBean<>(new MyServlet(), "/api/*");
        bean.setLoadOnStartup(1);
        bean.addInitParameter("encoding", "UTF-8");
        return bean;
    }

    @Bean
    public ServletRegistrationBean<FileUploadServlet> fileUploadServlet() {
        ServletRegistrationBean<FileUploadServlet> bean =
            new ServletRegistrationBean<>(new FileUploadServlet(), "/upload/*");

        MultipartConfigElement multipart = new MultipartConfigElement(
            "/tmp",           // location
            10485760,         // maxFileSize (10MB)
            20971520,         // maxRequestSize (20MB)
            5242880          // fileSizeThreshold (5MB)
        );
        bean.setMultipartConfig(multipart);

        return bean;
    }
}

AbstractFilterRegistrationBean

Abstract base class for filter registration beans that provides common filter configuration functionality.

package org.springframework.boot.web.servlet;

/**
 * Abstract base ServletContextInitializer to register Filters in a
 * Servlet 3.0+ container.
 *
 * @param <T> the type of Filter to register
 * @since 1.5.22
 */
public abstract class AbstractFilterRegistrationBean<T extends Filter>
        extends DynamicRegistrationBean<FilterRegistration.Dynamic> {

    /**
     * Create a new instance to be registered with the specified
     * ServletRegistrationBeans.
     *
     * @param servletRegistrationBeans associate ServletRegistrationBeans
     */
    AbstractFilterRegistrationBean(ServletRegistrationBean<?>... servletRegistrationBeans) { }

    /**
     * Set ServletRegistrationBeans that the filter will be registered against.
     *
     * @param servletRegistrationBeans the Servlet registration beans
     */
    public void setServletRegistrationBeans(
            Collection<? extends ServletRegistrationBean<?>> servletRegistrationBeans) { }

    /**
     * Return a mutable collection of the ServletRegistrationBean that the filter
     * will be registered against.
     *
     * @return the Servlet registration beans
     */
    public Collection<ServletRegistrationBean<?>> getServletRegistrationBeans() { }

    /**
     * Add ServletRegistrationBeans for the filter.
     *
     * @param servletRegistrationBeans the servlet registration beans to add
     */
    public void addServletRegistrationBeans(
            ServletRegistrationBean<?>... servletRegistrationBeans) { }

    /**
     * Set servlet names that the filter will be registered against.
     *
     * @param servletNames the servlet names
     */
    public void setServletNames(Collection<String> servletNames) { }

    /**
     * Return a mutable collection of servlet names that the filter will be
     * registered against.
     *
     * @return the servlet names
     */
    public Collection<String> getServletNames() { }

    /**
     * Add servlet names for the filter.
     *
     * @param servletNames the servlet names to add
     */
    public void addServletNames(String... servletNames) { }

    /**
     * Set the URL patterns that the filter will be registered against.
     *
     * @param urlPatterns the URL patterns
     */
    public void setUrlPatterns(Collection<String> urlPatterns) { }

    /**
     * Return a mutable collection of URL patterns, as defined in the Servlet
     * specification, that the filter will be registered against.
     *
     * @return the URL patterns
     */
    public Collection<String> getUrlPatterns() { }

    /**
     * Add URL patterns, as defined in the Servlet specification, that the filter
     * will be registered against.
     *
     * @param urlPatterns the URL patterns
     */
    public void addUrlPatterns(String... urlPatterns) { }

    /**
     * Determines the DispatcherType dispatcher types for which the filter should
     * be registered.
     *
     * @return the dispatcher types, never null
     * @since 3.2.0
     */
    public EnumSet<DispatcherType> determineDispatcherTypes() { }

    /**
     * Convenience method to set dispatcher types using the specified elements.
     *
     * @param first the first dispatcher type
     * @param rest additional dispatcher types
     */
    public void setDispatcherTypes(DispatcherType first, DispatcherType... rest) { }

    /**
     * Sets the dispatcher types that should be used with the registration.
     *
     * @param dispatcherTypes the dispatcher types
     */
    public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes) { }

    /**
     * Set if the filter mappings should be matched after any declared filter
     * mappings of the ServletContext.
     *
     * @param matchAfter if filter mappings are matched after
     */
    public void setMatchAfter(boolean matchAfter) { }

    /**
     * Return if filter mappings should be matched after any declared Filter
     * mappings of the ServletContext.
     *
     * @return if filter mappings are matched after
     */
    public boolean isMatchAfter() { }

    /**
     * Return the Filter to be registered.
     *
     * @return the filter
     */
    public abstract T getFilter();

    /**
     * Returns the filter name that will be registered.
     *
     * @return the filter name
     * @since 3.2.0
     */
    public String getFilterName() { }
}

FilterRegistrationBean

A ServletContextInitializer to register filters in a Servlet 3.0+ container.

package org.springframework.boot.web.servlet;

/**
 * A ServletContextInitializer to register Filters in a Servlet 3.0+ container.
 * Similar to ServletContext.addFilter() but with a Spring Bean friendly design.
 *
 * The Filter must be specified before calling onStartup. Registrations can be
 * associated with URL patterns and/or servlets. When no URL pattern or servlets
 * are specified, the filter will be associated to '/*'.
 *
 * @param <T> the type of Filter to register
 * @since 1.4.0
 */
public class FilterRegistrationBean<T extends Filter>
        extends AbstractFilterRegistrationBean<T> {

    /**
     * Create a new FilterRegistrationBean instance.
     */
    public FilterRegistrationBean() { }

    /**
     * Create a new FilterRegistrationBean instance to be registered with
     * the specified ServletRegistrationBeans.
     *
     * @param filter the filter to register
     * @param servletRegistrationBeans associate ServletRegistrationBeans
     */
    public FilterRegistrationBean(T filter,
                                 ServletRegistrationBean<?>... servletRegistrationBeans) { }

    /**
     * Return the filter being registered.
     *
     * @return the filter
     */
    public T getFilter() { }

    /**
     * Set the filter to be registered.
     *
     * @param filter the filter
     */
    public void setFilter(T filter) { }
}

Usage Example:

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<LoggingFilter> loggingFilter() {
        FilterRegistrationBean<LoggingFilter> bean =
            new FilterRegistrationBean<>(new LoggingFilter());
        bean.addUrlPatterns("/api/*");
        bean.setOrder(1);
        return bean;
    }

    @Bean
    public FilterRegistrationBean<CharacterEncodingFilter> encodingFilter() {
        FilterRegistrationBean<CharacterEncodingFilter> bean =
            new FilterRegistrationBean<>();

        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);

        bean.setFilter(filter);
        bean.addUrlPatterns("/*");
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);

        return bean;
    }
}

ServletListenerRegistrationBean

A ServletContextInitializer to register event listeners in a Servlet 3.0+ container.

package org.springframework.boot.web.servlet;

/**
 * A ServletContextInitializer to register EventListeners in a Servlet 3.0+
 * container. Similar to ServletContext.addListener() but with a Spring Bean
 * friendly design.
 *
 * This bean can be used to register the following types of listener:
 * - ServletContextAttributeListener
 * - ServletRequestListener
 * - ServletRequestAttributeListener
 * - HttpSessionAttributeListener
 * - HttpSessionIdListener
 * - HttpSessionListener
 * - ServletContextListener
 *
 * @param <T> the type of listener
 * @since 1.4.0
 */
public class ServletListenerRegistrationBean<T extends EventListener>
        extends RegistrationBean {

    /**
     * Create a new ServletListenerRegistrationBean instance.
     */
    public ServletListenerRegistrationBean() { }

    /**
     * Create a new ServletListenerRegistrationBean instance.
     *
     * @param listener the listener to register
     */
    public ServletListenerRegistrationBean(T listener) { }

    /**
     * Set the listener that will be registered.
     *
     * @param listener the listener to register
     */
    public void setListener(T listener) { }

    /**
     * Return the listener to be registered.
     *
     * @return the listener to be registered
     */
    public T getListener() { }

    /**
     * Returns true if the specified listener is one of the supported types.
     *
     * @param listener the listener to test
     * @return if the listener is of a supported type
     */
    public static boolean isSupportedType(EventListener listener) { }

    /**
     * Return the supported types for this registration.
     *
     * @return the supported types
     */
    public static Set<Class<?>> getSupportedTypes() { }
}

Usage Example:

@Configuration
public class ListenerConfig {

    @Bean
    public ServletListenerRegistrationBean<SessionListener> sessionListener() {
        return new ServletListenerRegistrationBean<>(new SessionListener());
    }

    @Bean
    public ServletListenerRegistrationBean<RequestListener> requestListener() {
        ServletListenerRegistrationBean<RequestListener> bean =
            new ServletListenerRegistrationBean<>();
        bean.setListener(new RequestListener());
        bean.setOrder(1);
        return bean;
    }
}

// Custom session listener
class SessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("Session created: " + se.getSession().getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Session destroyed: " + se.getSession().getId());
    }
}

DelegatingFilterProxyRegistrationBean

A ServletContextInitializer to register DelegatingFilterProxy instances that delegate to Spring-managed filter beans.

package org.springframework.boot.web.servlet;

/**
 * A ServletContextInitializer to register DelegatingFilterProxys in a
 * Servlet 3.0+ container. Unlike FilterRegistrationBean, referenced filters
 * are not instantiated early. If the delegate filter bean is marked @Lazy,
 * it won't be instantiated until the filter is called.
 *
 * The targetBeanName will be used as the filter name if not otherwise specified.
 *
 * @since 1.4.0
 */
public class DelegatingFilterProxyRegistrationBean
        extends AbstractFilterRegistrationBean<DelegatingFilterProxy>
        implements ApplicationContextAware {

    /**
     * Create a new DelegatingFilterProxyRegistrationBean instance to be
     * registered with the specified ServletRegistrationBeans.
     *
     * @param targetBeanName name of the target filter bean to look up in
     *                       the Spring application context (must not be null)
     * @param servletRegistrationBeans associate ServletRegistrationBeans
     */
    public DelegatingFilterProxyRegistrationBean(
            String targetBeanName,
            ServletRegistrationBean<?>... servletRegistrationBeans) { }

    /**
     * Get the target bean name.
     *
     * @return the target bean name
     */
    protected String getTargetBeanName() { }

    /**
     * Return the filter to be registered.
     *
     * @return the filter
     */
    @Override
    public DelegatingFilterProxy getFilter() { }
}

Usage Example:

@Configuration
public class SecurityFilterConfig {

    @Bean
    public DelegatingFilterProxyRegistrationBean securityFilterChain() {
        DelegatingFilterProxyRegistrationBean bean =
            new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain");
        bean.addUrlPatterns("/*");
        bean.setOrder(SecurityProperties.DEFAULT_FILTER_ORDER);
        return bean;
    }

    // The actual filter bean (can be @Lazy)
    @Bean("springSecurityFilterChain")
    @Lazy
    public Filter springSecurityFilterChain() {
        return new CustomSecurityFilter();
    }
}

RegistrationBean

Base class for all servlet registration beans.

package org.springframework.boot.web.servlet;

/**
 * Base class for Servlet 3.0+ based registration beans.
 *
 * @since 1.4.0
 */
public abstract class RegistrationBean
        implements ServletContextInitializer, Ordered {

    /**
     * Flag to indicate that the registration is enabled.
     *
     * @param enabled the enabled to set
     */
    public void setEnabled(boolean enabled) { }

    /**
     * Return if the registration is enabled.
     *
     * @return if enabled (default true)
     */
    public boolean isEnabled() { }

    /**
     * Set the order of the registration bean.
     *
     * @param order the order
     */
    public void setOrder(int order) { }

    /**
     * Get the order of the registration bean.
     *
     * @return the order
     */
    @Override
    public int getOrder() { }

    /**
     * Return a description of the registration.
     *
     * @return a description of the registration
     */
    protected abstract String getDescription();

    /**
     * Register this bean with the servlet context.
     *
     * @param description a description of the item being registered
     * @param servletContext the servlet context
     */
    protected abstract void register(String description, ServletContext servletContext);
}

Servlet Context Support

Spring Boot provides specialized application contexts and environments for servlet-based web applications.

AnnotationConfigServletWebApplicationContext

An annotation-based servlet web application context.

package org.springframework.boot.web.context.servlet;

/**
 * GenericWebApplicationContext that accepts annotated classes as input -
 * in particular @Configuration-annotated classes, but also plain @Component
 * classes and JSR-330 compliant classes using javax.inject annotations.
 *
 * Allows for registering classes one by one (specifying class names as config
 * location) as well as for classpath scanning (specifying base packages as
 * config location).
 *
 * Note: In case of multiple @Configuration classes, later @Bean definitions
 * will override ones defined in earlier loaded files.
 *
 * @since 2.2.0
 */
public class AnnotationConfigServletWebApplicationContext
        extends GenericWebApplicationContext
        implements AnnotationConfigRegistry {

    /**
     * Create a new AnnotationConfigServletWebApplicationContext that needs
     * to be populated through register calls and then manually refreshed.
     */
    public AnnotationConfigServletWebApplicationContext() { }

    /**
     * Create a new AnnotationConfigServletWebApplicationContext with the
     * given DefaultListableBeanFactory.
     *
     * @param beanFactory the DefaultListableBeanFactory instance to use
     *                    for this context
     */
    public AnnotationConfigServletWebApplicationContext(
            DefaultListableBeanFactory beanFactory) { }

    /**
     * Create a new AnnotationConfigServletWebApplicationContext, deriving
     * bean definitions from the given annotated classes and automatically
     * refreshing the context.
     *
     * @param annotatedClasses one or more annotated classes,
     *                         e.g. @Configuration classes
     */
    public AnnotationConfigServletWebApplicationContext(
            Class<?>... annotatedClasses) { }

    /**
     * Create a new AnnotationConfigServletWebApplicationContext, scanning
     * for bean definitions in the given packages and automatically
     * refreshing the context.
     *
     * @param basePackages the packages to check for annotated classes
     */
    public AnnotationConfigServletWebApplicationContext(String... basePackages) { }

    /**
     * Set the Environment to use.
     *
     * @param environment the environment
     */
    @Override
    public void setEnvironment(ConfigurableEnvironment environment) { }

    /**
     * Provide a custom BeanNameGenerator for use with
     * AnnotatedBeanDefinitionReader and/or ClassPathBeanDefinitionScanner.
     *
     * @param beanNameGenerator the bean name generator
     */
    public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { }

    /**
     * Set the ScopeMetadataResolver to use for detected bean classes.
     *
     * @param scopeMetadataResolver the scope metadata resolver
     */
    public void setScopeMetadataResolver(
            ScopeMetadataResolver scopeMetadataResolver) { }

    /**
     * Register one or more annotated classes to be processed.
     *
     * @param annotatedClasses one or more annotated classes,
     *                         e.g. @Configuration classes
     */
    @Override
    public final void register(Class<?>... annotatedClasses) { }

    /**
     * Perform a scan within the specified base packages.
     *
     * @param basePackages the packages to check for annotated classes
     */
    @Override
    public final void scan(String... basePackages) { }
}

Usage Example:

public class WebApplicationBootstrap {

    public static void main(String[] args) {
        // Create context with configuration classes
        AnnotationConfigServletWebApplicationContext context =
            new AnnotationConfigServletWebApplicationContext(AppConfig.class);

        // Or create and configure manually
        AnnotationConfigServletWebApplicationContext context2 =
            new AnnotationConfigServletWebApplicationContext();
        context2.register(AppConfig.class, WebConfig.class);
        context2.scan("com.example.controllers");
        context2.refresh();
    }
}

ApplicationServletEnvironment

The standard servlet environment for Spring Boot applications.

package org.springframework.boot.web.context.servlet;

/**
 * StandardServletEnvironment for typical use in a typical SpringApplication.
 *
 * @since 4.0.0
 */
public class ApplicationServletEnvironment extends StandardServletEnvironment {

    /**
     * Return the active profiles property name (returns null to delegate
     * to Spring Boot's profile management).
     *
     * @return null
     */
    @Override
    protected String doGetActiveProfilesProperty() { }

    /**
     * Return the default profiles property name (returns null to delegate
     * to Spring Boot's profile management).
     *
     * @return null
     */
    @Override
    protected String doGetDefaultProfilesProperty() { }

    /**
     * Create a property resolver that uses ConfigurationPropertySources.
     *
     * @param propertySources the property sources
     * @return the configured property resolver
     */
    @Override
    protected ConfigurablePropertyResolver createPropertyResolver(
            MutablePropertySources propertySources) { }
}

SpringBootServletInitializer

An opinionated WebApplicationInitializer to run a SpringApplication from a traditional WAR deployment.

package org.springframework.boot.web.servlet.support;

/**
 * An opinionated WebApplicationInitializer to run a SpringApplication from
 * a traditional WAR deployment. Binds Servlet, Filter and ServletContextInitializer
 * beans from the application context to the server.
 *
 * To configure the application, either override the configure() method or
 * make the initializer itself a @Configuration.
 *
 * Note: A WebApplicationInitializer is only needed if you are building a
 * war file. If you prefer to run an embedded web server, you won't need this.
 *
 * @since 2.0.0
 */
public abstract class SpringBootServletInitializer
        implements WebApplicationInitializer {

    /**
     * Set if the ErrorPageFilter should be registered. Set to false if
     * error page mappings should be handled through the server and not
     * Spring Boot.
     *
     * @param registerErrorPageFilter if the ErrorPageFilter should be registered
     */
    protected final void setRegisterErrorPageFilter(
            boolean registerErrorPageFilter) { }

    /**
     * Called when the servlet container starts up the application.
     *
     * @param servletContext the servlet context
     * @throws ServletException if startup fails
     */
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException { }

    /**
     * Deregisters the JDBC drivers that were registered by the application.
     *
     * @param servletContext the web application's servlet context
     * @since 2.3.0
     */
    protected void deregisterJdbcDrivers(ServletContext servletContext) { }

    /**
     * Shuts down the reactor Schedulers that were initialized.
     *
     * @param servletContext the web application's servlet context
     * @since 3.4.0
     */
    protected void shutDownSharedReactorSchedulers(ServletContext servletContext) { }

    /**
     * Creates the root application context.
     *
     * @param servletContext the servlet context
     * @return the root application context
     */
    protected WebApplicationContext createRootApplicationContext(
            ServletContext servletContext) { }

    /**
     * Returns the SpringApplicationBuilder that is used to configure and
     * create the SpringApplication.
     *
     * @return the SpringApplicationBuilder
     */
    protected SpringApplicationBuilder createSpringApplicationBuilder() { }

    /**
     * Called to run a fully configured SpringApplication.
     *
     * @param application the application to run
     * @return the WebApplicationContext
     */
    protected WebApplicationContext run(SpringApplication application) { }

    /**
     * Configure the application. Normally all you would need to do is add
     * sources (e.g. config classes).
     *
     * @param builder a builder for the application context
     * @return the application builder
     */
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { }
}

Usage Example:

public class MyWebAppInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(MyApplication.class);
    }

    // Optional: disable error page filter if server handles errors
    public MyWebAppInitializer() {
        setRegisterErrorPageFilter(false);
    }
}

// Then package as WAR and deploy to servlet container

ErrorPageFilter

A servlet filter that provides error page handling for non-embedded applications.

package org.springframework.boot.web.servlet.support;

/**
 * A Servlet Filter that provides an ErrorPageRegistry for non-embedded
 * applications (i.e. deployed WAR files). It registers error pages and
 * handles application errors by filtering requests and forwarding to the
 * error pages instead of letting the server handle them.
 *
 * @since 2.0.0
 */
public class ErrorPageFilter implements Filter, ErrorPageRegistry, Ordered {

    /**
     * The name of the servlet attribute containing request URI.
     */
    public static final String ERROR_REQUEST_URI =
        "jakarta.servlet.error.request_uri";

    /**
     * Initialize the filter.
     *
     * @param filterConfig the filter configuration
     * @throws ServletException if initialization fails
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    /**
     * Apply the filter.
     *
     * @param request the servlet request
     * @param response the servlet response
     * @param chain the filter chain
     * @throws IOException if an I/O error occurs
     * @throws ServletException if a servlet error occurs
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException { }

    /**
     * Add error pages to be handled by this filter.
     *
     * @param errorPages the error pages
     */
    @Override
    public void addErrorPages(ErrorPage... errorPages) { }

    /**
     * Destroy the filter.
     */
    @Override
    public void destroy() { }

    /**
     * Get the order of this filter.
     *
     * @return the order (HIGHEST_PRECEDENCE + 1)
     */
    @Override
    public int getOrder() { }

    /**
     * Return a description for the given request.
     *
     * @param request the source request
     * @return the description
     */
    protected String getDescription(HttpServletRequest request) { }
}

Usage Example:

@Configuration
public class ErrorPageConfig {

    @Bean
    public ErrorPageFilter errorPageFilter() {
        ErrorPageFilter filter = new ErrorPageFilter();
        filter.addErrorPages(
            new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
            new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
            new ErrorPage(Exception.class, "/error/exception")
        );
        return filter;
    }
}

Reactive Support

Spring Boot provides comprehensive support for reactive web applications using Project Reactor and Spring WebFlux.

ReactiveWebApplicationContext

The marker interface for reactive web application contexts.

package org.springframework.boot.web.context.reactive;

/**
 * Interface to provide configuration for a reactive web application.
 *
 * @since 2.0.0
 */
public interface ReactiveWebApplicationContext extends ApplicationContext {
    // Marker interface
}

ConfigurableReactiveWebApplicationContext

A configurable reactive web application context interface.

package org.springframework.boot.web.context.reactive;

/**
 * Configurable interface for reactive web application contexts.
 *
 * @since 2.0.0
 */
public interface ConfigurableReactiveWebApplicationContext
        extends ConfigurableApplicationContext, ReactiveWebApplicationContext {
    // Combined interface for configuration and reactive web support
}

AnnotationConfigReactiveWebApplicationContext

An annotation-based reactive web application context.

package org.springframework.boot.web.context.reactive;

/**
 * ConfigurableReactiveWebApplicationContext that accepts annotated classes
 * as input - in particular @Configuration-annotated classes, but also plain
 * @Component classes and JSR-330 compliant classes.
 *
 * Allows for registering classes one by one or for classpath scanning.
 *
 * Note: In case of multiple @Configuration classes, later @Bean definitions
 * will override ones defined in earlier loaded files.
 *
 * @since 2.0.0
 */
public class AnnotationConfigReactiveWebApplicationContext
        extends AnnotationConfigApplicationContext
        implements ConfigurableReactiveWebApplicationContext {

    /**
     * Create a new AnnotationConfigReactiveWebApplicationContext that needs
     * to be populated through register calls and then manually refreshed.
     */
    public AnnotationConfigReactiveWebApplicationContext() { }

    /**
     * Create a new AnnotationConfigReactiveWebApplicationContext with the
     * given DefaultListableBeanFactory.
     *
     * @param beanFactory the DefaultListableBeanFactory instance to use
     *                    for this context
     * @since 2.2.0
     */
    public AnnotationConfigReactiveWebApplicationContext(
            DefaultListableBeanFactory beanFactory) { }

    /**
     * Create a new AnnotationConfigReactiveWebApplicationContext, deriving
     * bean definitions from the given annotated classes and automatically
     * refreshing the context.
     *
     * @param annotatedClasses one or more annotated classes,
     *                         e.g. @Configuration classes
     * @since 2.2.0
     */
    public AnnotationConfigReactiveWebApplicationContext(
            Class<?>... annotatedClasses) { }

    /**
     * Create a new AnnotationConfigReactiveWebApplicationContext, scanning
     * for bean definitions in the given packages and automatically refreshing
     * the context.
     *
     * @param basePackages the packages to check for annotated classes
     * @since 2.2.0
     */
    public AnnotationConfigReactiveWebApplicationContext(String... basePackages) { }

    /**
     * Create the environment for this context.
     *
     * @return a new StandardReactiveWebEnvironment
     */
    @Override
    protected ConfigurableEnvironment createEnvironment() { }

    /**
     * Get a resource by path, ensuring classpath resources are not exposed.
     *
     * @param path the resource path
     * @return the resource
     */
    @Override
    protected Resource getResourceByPath(String path) { }
}

Usage Example:

@Configuration
@EnableWebFlux
public class ReactiveWebConfig {

    public static void main(String[] args) {
        // Create reactive context
        AnnotationConfigReactiveWebApplicationContext context =
            new AnnotationConfigReactiveWebApplicationContext(
                ReactiveWebConfig.class
            );

        // Or configure manually
        AnnotationConfigReactiveWebApplicationContext context2 =
            new AnnotationConfigReactiveWebApplicationContext();
        context2.register(ReactiveWebConfig.class);
        context2.scan("com.example.handlers");
        context2.refresh();
    }

    @Bean
    public RouterFunction<ServerResponse> routes(UserHandler handler) {
        return RouterFunctions.route()
            .GET("/users", handler::listUsers)
            .GET("/users/{id}", handler::getUser)
            .POST("/users", handler::createUser)
            .build();
    }
}

GenericReactiveWebApplicationContext

A generic reactive web application context.

package org.springframework.boot.web.context.reactive;

/**
 * Subclass of GenericApplicationContext, suitable for reactive web environments.
 *
 * @since 2.0.0
 */
public class GenericReactiveWebApplicationContext
        extends GenericApplicationContext
        implements ConfigurableReactiveWebApplicationContext {

    /**
     * Create a new GenericReactiveWebApplicationContext.
     */
    public GenericReactiveWebApplicationContext() { }

    /**
     * Create a new GenericReactiveWebApplicationContext with the given
     * DefaultListableBeanFactory.
     *
     * @param beanFactory the DefaultListableBeanFactory instance to use
     *                    for this context
     */
    public GenericReactiveWebApplicationContext(
            DefaultListableBeanFactory beanFactory) { }

    /**
     * Create the environment for this context.
     *
     * @return a new StandardReactiveWebEnvironment
     */
    @Override
    protected ConfigurableEnvironment createEnvironment() { }

    /**
     * Get a resource by path, ensuring classpath resources are not exposed.
     *
     * @param path the resource path
     * @return the resource
     */
    @Override
    protected Resource getResourceByPath(String path) { }
}

StandardReactiveWebEnvironment

The standard environment implementation for reactive web applications.

package org.springframework.boot.web.context.reactive;

/**
 * Environment implementation to be used by Reactive-based web applications.
 * All web-related (reactive-based) ApplicationContext classes initialize
 * an instance by default.
 *
 * @since 2.0.0
 */
public class StandardReactiveWebEnvironment extends StandardEnvironment
        implements ConfigurableReactiveWebEnvironment {

    /**
     * Create a new StandardReactiveWebEnvironment.
     */
    public StandardReactiveWebEnvironment() { }

    /**
     * Create a new StandardReactiveWebEnvironment with the given property sources.
     *
     * @param propertySources the property sources
     */
    protected StandardReactiveWebEnvironment(MutablePropertySources propertySources) { }
}

Usage Example:

@SpringBootApplication
public class ReactiveApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(ReactiveApplication.class);
        app.setWebApplicationType(WebApplicationType.REACTIVE);
        app.run(args);
    }
}

@RestController
@RequestMapping("/api")
public class ReactiveController {

    @GetMapping("/users")
    public Flux<User> getUsers() {
        return userRepository.findAll();
    }

    @GetMapping("/users/{id}")
    public Mono<User> getUser(@PathVariable String id) {
        return userRepository.findById(id);
    }

    @PostMapping("/users")
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}

Error Page Support

Spring Boot provides a comprehensive error page mechanism for customizing error responses.

ErrorPage

A simple server-independent abstraction for error pages.

package org.springframework.boot.web.error;

/**
 * Simple server-independent abstraction for error pages. Roughly equivalent
 * to the <error-page> element traditionally found in web.xml.
 *
 * @since 4.0.0
 */
public class ErrorPage {

    /**
     * Create a global error page (matches all unmatched errors).
     *
     * @param path the path to render
     */
    public ErrorPage(String path) { }

    /**
     * Create an error page for a specific HTTP status.
     *
     * @param status the HTTP status
     * @param path the path to render
     */
    public ErrorPage(HttpStatus status, String path) { }

    /**
     * Create an error page for a specific exception type.
     *
     * @param exception the exception class
     * @param path the path to render
     */
    public ErrorPage(Class<? extends Throwable> exception, String path) { }

    /**
     * The path to render (usually implemented as a forward), starting with "/".
     *
     * @return the path that will be rendered for this error
     */
    public String getPath() { }

    /**
     * Returns the exception type (or null for a page that matches by status).
     *
     * @return the exception type or null
     */
    public Class<? extends Throwable> getException() { }

    /**
     * The HTTP status value that this error page matches (or null for a page
     * that matches by exception).
     *
     * @return the status or null
     */
    public HttpStatus getStatus() { }

    /**
     * The HTTP status value that this error page matches.
     *
     * @return the status value (or 0 for a page that matches any status)
     */
    public int getStatusCode() { }

    /**
     * The exception type name.
     *
     * @return the exception type name (or null if there is none)
     */
    public String getExceptionName() { }

    /**
     * Return if this error page is a global one (matches all unmatched
     * status and exception types).
     *
     * @return if this is a global error page
     */
    public boolean isGlobal() { }
}

Usage Example:

@Configuration
public class ErrorPageConfiguration {

    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return registry -> {
            // Status-based error pages
            registry.addErrorPages(
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.FORBIDDEN, "/error/403"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
            );

            // Exception-based error pages
            registry.addErrorPages(
                new ErrorPage(IllegalArgumentException.class, "/error/bad-request"),
                new ErrorPage(DataAccessException.class, "/error/database")
            );

            // Global error page (catches all unmatched errors)
            registry.addErrorPages(new ErrorPage("/error/general"));
        };
    }
}

@Controller
public class ErrorController {

    @RequestMapping("/error/404")
    public String notFound(Model model) {
        model.addAttribute("message", "Page not found");
        return "error/404";
    }

    @RequestMapping("/error/500")
    public String serverError(Model model) {
        model.addAttribute("message", "Internal server error");
        return "error/500";
    }
}

ErrorPageRegistry

An interface for registries that hold error pages.

package org.springframework.boot.web.error;

/**
 * Interface for a registry that holds ErrorPages.
 *
 * @since 4.0.0
 */
@FunctionalInterface
public interface ErrorPageRegistry {

    /**
     * Adds error pages that will be used when handling exceptions.
     *
     * @param errorPages the error pages
     */
    void addErrorPages(ErrorPage... errorPages);
}

ErrorPageRegistrar

An interface for types that register error pages.

package org.springframework.boot.web.error;

/**
 * Interface to be implemented by types that register ErrorPages.
 *
 * @since 4.0.0
 */
@FunctionalInterface
public interface ErrorPageRegistrar {

    /**
     * Register pages as required with the given registry.
     *
     * @param registry the error page registry
     */
    void registerErrorPages(ErrorPageRegistry registry);
}

Usage Example:

@Component
public class CustomErrorPageRegistrar implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        // Register custom error pages
        registry.addErrorPages(
            new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400"),
            new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401"),
            new ErrorPage(HttpStatus.PAYMENT_REQUIRED, "/error/402"),
            new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
            new ErrorPage(HttpStatus.METHOD_NOT_ALLOWED, "/error/405")
        );
    }
}

ErrorAttributeOptions

Options controlling the contents of error attributes.

package org.springframework.boot.web.error;

/**
 * Options controlling the contents of ErrorAttributes.
 *
 * @since 2.3.0
 */
public final class ErrorAttributeOptions {

    /**
     * Get the option for including the specified attribute in the error response.
     *
     * @param include error attribute to get
     * @return true if the Include attribute is included in the error response
     */
    public boolean isIncluded(Include include) { }

    /**
     * Get all options for including attributes in the error response.
     *
     * @return the options
     */
    public Set<Include> getIncludes() { }

    /**
     * Return an ErrorAttributeOptions that includes the specified attribute
     * Include options.
     *
     * @param includes error attributes to include
     * @return an ErrorAttributeOptions
     */
    public ErrorAttributeOptions including(Include... includes) { }

    /**
     * Return an ErrorAttributeOptions that excludes the specified attribute
     * Include options.
     *
     * @param excludes error attributes to exclude
     * @return an ErrorAttributeOptions
     */
    public ErrorAttributeOptions excluding(Include... excludes) { }

    /**
     * Remove elements from the given map if they are not included in this
     * set of options.
     *
     * @param map the map to update
     * @since 3.2.7
     */
    public void retainIncluded(Map<String, Object> map) { }

    /**
     * Create an ErrorAttributeOptions with defaults.
     *
     * @return an ErrorAttributeOptions
     */
    public static ErrorAttributeOptions defaults() { }

    /**
     * Create an ErrorAttributeOptions that includes the specified attribute
     * Include options.
     *
     * @param includes error attributes to include
     * @return an ErrorAttributeOptions
     */
    public static ErrorAttributeOptions of(Include... includes) { }

    /**
     * Create an ErrorAttributeOptions that includes the specified attribute
     * Include options.
     *
     * @param includes error attributes to include
     * @return an ErrorAttributeOptions
     */
    public static ErrorAttributeOptions of(Collection<Include> includes) { }

    /**
     * Error attributes that can be included in an error response.
     */
    public enum Include {
        /**
         * Include the exception class name attribute.
         */
        EXCEPTION,

        /**
         * Include the stack trace attribute.
         */
        STACK_TRACE,

        /**
         * Include the message attribute.
         */
        MESSAGE,

        /**
         * Include the binding errors attribute.
         */
        BINDING_ERRORS,

        /**
         * Include the HTTP status code.
         *
         * @since 3.2.7
         */
        STATUS,

        /**
         * Include the error type.
         *
         * @since 3.2.7
         */
        ERROR,

        /**
         * Include the request path.
         *
         * @since 3.3.0
         */
        PATH
    }
}

Usage Example:

@ControllerAdvice
public class CustomErrorAttributes extends DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest,
                                                   ErrorAttributeOptions options) {
        // Create custom options
        ErrorAttributeOptions customOptions = ErrorAttributeOptions.of(
            Include.MESSAGE,
            Include.STATUS,
            Include.ERROR,
            Include.PATH
        );

        // Or modify existing options
        ErrorAttributeOptions withStack = options.including(Include.STACK_TRACE);
        ErrorAttributeOptions withoutBinding = options.excluding(Include.BINDING_ERRORS);

        // Get error attributes with custom options
        Map<String, Object> errorAttributes =
            super.getErrorAttributes(webRequest, customOptions);

        // Add custom attributes
        errorAttributes.put("timestamp", LocalDateTime.now());
        errorAttributes.put("support", "contact@example.com");

        return errorAttributes;
    }
}

@RestControllerAdvice
public class ApiErrorHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Map<String, Object>> handleException(
            Exception ex, WebRequest request) {

        // Use ErrorAttributeOptions to control what gets included
        ErrorAttributeOptions options = ErrorAttributeOptions
            .defaults()
            .including(Include.MESSAGE, Include.STACK_TRACE);

        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("message", ex.getMessage());

        // Only include stack trace in development
        if (options.isIncluded(Include.STACK_TRACE)) {
            body.put("trace", getStackTrace(ex));
        }

        return ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(body);
    }
}

Error

A wrapper class for MessageSourceResolvable errors that is safe for JSON serialization.

package org.springframework.boot.web.error;

/**
 * A wrapper class for MessageSourceResolvable errors that is safe for JSON
 * serialization.
 *
 * @since 3.5.0
 */
public final class Error implements MessageSourceResolvable {

    /**
     * Get the codes for message resolution.
     *
     * @return the codes (may be null)
     */
    @Override
    public String[] getCodes();

    /**
     * Get the arguments for message resolution.
     *
     * @return the arguments (may be null)
     */
    @Override
    public Object[] getArguments();

    /**
     * Get the default message.
     *
     * @return the default message (may be null)
     */
    @Override
    public String getDefaultMessage();

    /**
     * Return the original cause of the error.
     *
     * @return the error cause
     */
    @JsonIgnore
    public MessageSourceResolvable getCause();

    /**
     * Wrap the given errors, if necessary, such that they are suitable for serialization
     * to JSON. MessageSourceResolvable implementations that are known to be
     * suitable are not wrapped.
     *
     * @param errors the errors to wrap
     * @return a new Error list
     * @since 3.5.4
     */
    public static List<MessageSourceResolvable> wrapIfNecessary(
            List<? extends MessageSourceResolvable> errors);
}

Usage Example:

import org.springframework.boot.web.error.Error;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.validation.FieldError;

@RestControllerAdvice
public class ValidationErrorHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> handleValidationErrors(
            MethodArgumentNotValidException ex) {

        // Get validation errors
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();

        // Wrap errors for JSON serialization
        List<MessageSourceResolvable> wrapped = Error.wrapIfNecessary(fieldErrors);

        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", HttpStatus.BAD_REQUEST.value());
        body.put("errors", wrapped);

        return ResponseEntity
            .status(HttpStatus.BAD_REQUEST)
            .body(body);
    }
}

Web Server Factory and Customization

Spring Boot provides a comprehensive set of interfaces and classes for creating and customizing embedded web servers.

WebServer

The core interface representing a fully configured web server that can be started and stopped.

package org.springframework.boot.web.server;

/**
 * Simple interface that represents a fully configured web server (for example
 * Tomcat, Jetty, Netty). Allows the server to be started and stopped.
 *
 * @since 2.0.0
 */
public interface WebServer {

    /**
     * Starts the web server. Calling this method on an already started server
     * has no effect.
     *
     * @throws WebServerException if the server cannot be started
     */
    void start() throws WebServerException;

    /**
     * Stops the web server. Calling this method on an already stopped server
     * has no effect.
     *
     * @throws WebServerException if the server cannot be stopped
     */
    void stop() throws WebServerException;

    /**
     * Return the port this server is listening on.
     *
     * @return the port (or -1 if none)
     */
    int getPort();

    /**
     * Initiates a graceful shutdown of the web server. Handling of new requests
     * is prevented and the given callback is invoked at the end of the attempt.
     *
     * @param callback the callback to invoke when the graceful shutdown completes
     * @since 2.3.0
     */
    default void shutDownGracefully(GracefulShutdownCallback callback) {
        callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);
    }

    /**
     * Destroys the web server such that it cannot be started again.
     *
     * @since 3.2.0
     */
    default void destroy() {
        stop();
    }
}

GracefulShutdownCallback

A callback for the result of a graceful shutdown request.

package org.springframework.boot.web.server;

/**
 * A callback for the result of a graceful shutdown request.
 *
 * @since 2.3.0
 */
@FunctionalInterface
public interface GracefulShutdownCallback {

    /**
     * Graceful shutdown has completed with the given result.
     *
     * @param result the result of the shutdown
     */
    void shutdownComplete(GracefulShutdownResult result);
}

GracefulShutdownResult

The result of a graceful shutdown request.

package org.springframework.boot.web.server;

/**
 * The result of a graceful shutdown request.
 *
 * @since 2.3.0
 */
public enum GracefulShutdownResult {

    /**
     * Requests remained active at the end of the grace period.
     */
    REQUESTS_ACTIVE,

    /**
     * The server was idle with no active requests at the end of the grace period.
     */
    IDLE,

    /**
     * The server was shutdown immediately, ignoring any active requests.
     */
    IMMEDIATE
}

Shutdown

Configuration for shutting down a WebServer.

package org.springframework.boot.web.server;

/**
 * Configuration for shutting down a WebServer.
 *
 * @since 2.3.0
 */
public enum Shutdown {

    /**
     * The WebServer should support graceful shutdown, allowing active
     * requests time to complete.
     */
    GRACEFUL,

    /**
     * The WebServer should shut down immediately.
     */
    IMMEDIATE
}

WebServerFactory

Tagging interface for factories that create a WebServer.

package org.springframework.boot.web.server;

/**
 * Tagging interface for factories that create a WebServer.
 *
 * @since 2.0.0
 */
public interface WebServerFactory {
    // Marker interface
}

ConfigurableWebServerFactory

A configurable WebServerFactory with common configuration options.

package org.springframework.boot.web.server;

/**
 * A configurable WebServerFactory.
 *
 * @since 2.0.0
 */
public interface ConfigurableWebServerFactory
        extends WebServerFactory, ErrorPageRegistry {

    /**
     * Sets the port that the web server should listen on. If not specified
     * port '8080' will be used. Use port -1 to disable auto-start.
     *
     * @param port the port to set
     */
    void setPort(int port);

    /**
     * Sets the specific network address that the server should bind to.
     *
     * @param address the address to set (defaults to null)
     */
    void setAddress(InetAddress address);

    /**
     * Sets the error pages that will be used when handling exceptions.
     *
     * @param errorPages the error pages
     */
    void setErrorPages(Set<? extends ErrorPage> errorPages);

    /**
     * Sets the SSL configuration that will be applied to the server's
     * default connector.
     *
     * @param ssl the SSL configuration
     */
    void setSsl(Ssl ssl);

    /**
     * Sets the SSL bundles that can be used to configure SSL connections.
     *
     * @param sslBundles the SSL bundles
     * @since 3.1.0
     */
    void setSslBundles(SslBundles sslBundles);

    /**
     * Sets the HTTP/2 configuration that will be applied to the server.
     *
     * @param http2 the HTTP/2 configuration
     */
    void setHttp2(Http2 http2);

    /**
     * Sets the compression configuration that will be applied to the
     * server's default connector.
     *
     * @param compression the compression configuration
     */
    void setCompression(Compression compression);

    /**
     * Sets the server header value.
     *
     * @param serverHeader the server header value
     */
    void setServerHeader(String serverHeader);

    /**
     * Sets the shutdown configuration that will be applied to the server.
     *
     * @param shutdown the shutdown configuration
     * @since 2.3.0
     */
    default void setShutdown(Shutdown shutdown) { }
}

ServletWebServerFactory

Factory interface for creating servlet-based web servers.

package org.springframework.boot.web.server.servlet;

/**
 * Factory interface that can be used to create a WebServer.
 *
 * @since 4.0.0
 */
@FunctionalInterface
public interface ServletWebServerFactory extends WebServerFactory {

    /**
     * Gets a new fully configured but paused WebServer instance. Clients
     * should not be able to connect to the returned server until
     * WebServer.start() is called.
     *
     * @param initializers ServletContextInitializers that should be applied
     *                     as the server starts
     * @return a fully configured and started WebServer
     */
    WebServer getWebServer(ServletContextInitializer... initializers);
}

ConfigurableServletWebServerFactory

A configurable ServletWebServerFactory with servlet-specific configuration options.

package org.springframework.boot.web.server.servlet;

/**
 * A configurable ServletWebServerFactory.
 *
 * @since 4.0.0
 */
public interface ConfigurableServletWebServerFactory
        extends ConfigurableWebServerFactory, ServletWebServerFactory, WebListenerRegistry {

    /**
     * Gets the settings for this servlet web server factory.
     *
     * @return the servlet web server settings
     */
    ServletWebServerSettings getSettings();

    /**
     * Sets the context path for the web server. The context should start
     * with a "/" character but not end with a "/" character.
     *
     * @param contextPath the context path to set
     */
    default void setContextPath(String contextPath) {
        getSettings().setContextPath(ContextPath.of(contextPath));
    }

    /**
     * Returns the context path for the servlet web server.
     *
     * @return the context path
     */
    default String getContextPath() {
        return getSettings().getContextPath().toString();
    }

    /**
     * Sets the display name of the application deployed in the web server.
     *
     * @param displayName the displayName to set
     */
    default void setDisplayName(String displayName) {
        getSettings().setDisplayName(displayName);
    }

    /**
     * Sets the configuration that will be applied to the container's HTTP
     * session support.
     *
     * @param session the session configuration
     */
    default void setSession(Session session) {
        getSettings().setSession(session);
    }

    /**
     * Set if the DefaultServlet should be registered.
     *
     * @param registerDefaultServlet if the default servlet should be registered
     */
    default void setRegisterDefaultServlet(boolean registerDefaultServlet) {
        getSettings().setRegisterDefaultServlet(registerDefaultServlet);
    }

    /**
     * Sets the mime-type mappings.
     *
     * @param mimeMappings the mime type mappings
     */
    default void setMimeMappings(MimeMappings mimeMappings) {
        getSettings().setMimeMappings(mimeMappings);
    }

    /**
     * Sets the document root directory which will be used by the web
     * context to serve static files.
     *
     * @param documentRoot the document root or null if not required
     */
    default void setDocumentRoot(File documentRoot) {
        getSettings().setDocumentRoot(documentRoot);
    }

    /**
     * Sets ServletContextInitializers that should be applied in addition to
     * ServletWebServerFactory.getWebServer parameters.
     *
     * @param initializers the initializers to set
     */
    default void setInitializers(List<? extends ServletContextInitializer> initializers) {
        getSettings().setInitializers(initializers);
    }

    /**
     * Add ServletContextInitializers to those that should be applied.
     *
     * @param initializers the initializers to add
     */
    default void addInitializers(ServletContextInitializer... initializers) {
        getSettings().addInitializers(initializers);
    }

    /**
     * Sets the configuration that will be applied to the server's JSP servlet.
     *
     * @param jsp the JSP servlet configuration
     */
    default void setJsp(Jsp jsp) {
        getSettings().setJsp(jsp);
    }

    /**
     * Sets the init parameters that are applied to the container's ServletContext.
     *
     * @param initParameters the init parameters
     */
    default void setInitParameters(Map<String, String> initParameters) {
        getSettings().setInitParameters(initParameters);
    }
}

ReactiveWebServerFactory

Factory interface for creating reactive web servers.

package org.springframework.boot.web.server.reactive;

/**
 * Factory interface that can be used to create a reactive WebServer.
 *
 * @since 4.0.0
 */
@FunctionalInterface
public interface ReactiveWebServerFactory extends WebServerFactory {

    /**
     * Gets a new fully configured but paused WebServer instance. Clients
     * should not be able to connect to the returned server until
     * WebServer.start() is called.
     *
     * @param httpHandler the HTTP handler in charge of processing requests
     * @return a fully configured and started WebServer
     */
    WebServer getWebServer(HttpHandler httpHandler);
}

ConfigurableReactiveWebServerFactory

A configurable ReactiveWebServerFactory.

package org.springframework.boot.web.server.reactive;

/**
 * Configurable ReactiveWebServerFactory.
 *
 * @since 4.0.0
 */
public interface ConfigurableReactiveWebServerFactory
        extends ConfigurableWebServerFactory, ReactiveWebServerFactory {
    // Combined interface for configuration and reactive web support
}

WebServerFactoryCustomizer

Strategy interface for customizing web server factories.

package org.springframework.boot.web.server;

/**
 * Strategy interface for customizing WebServerFactory web server factories.
 * Any beans of this type will get a callback with the server factory before
 * the server itself is started, so you can set the port, address, error
 * pages etc.
 *
 * @param <T> the configurable web server factory
 * @since 2.0.0
 */
@FunctionalInterface
public interface WebServerFactoryCustomizer<T extends WebServerFactory> {

    /**
     * Customize the specified WebServerFactory.
     *
     * @param factory the web server factory to customize
     */
    void customize(T factory);
}

Usage Example:

@Configuration
public class WebServerConfiguration {

    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
            servletWebServerCustomizer() {
        return factory -> {
            // Customize port
            factory.setPort(9090);

            // Set context path
            factory.setContextPath("/myapp");

            // Configure session timeout
            Session session = new Session();
            session.setTimeout(Duration.ofMinutes(30));
            factory.setSession(session);

            // Add error pages
            factory.addErrorPages(
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
            );

            // Configure shutdown
            factory.setShutdown(Shutdown.GRACEFUL);
        };
    }

    @Bean
    public WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory>
            reactiveWebServerCustomizer() {
        return factory -> {
            factory.setPort(8081);

            // Configure SSL
            Ssl ssl = new Ssl();
            ssl.setEnabled(true);
            ssl.setKeyStore("classpath:keystore.jks");
            ssl.setKeyStorePassword("password");
            factory.setSsl(ssl);

            // Enable HTTP/2
            Http2 http2 = new Http2();
            http2.setEnabled(true);
            factory.setHttp2(http2);
        };
    }

    // Graceful shutdown example
    @Bean
    public ApplicationListener<ContextClosedEvent> gracefulShutdownListener(
            WebServerApplicationContext context) {
        return event -> {
            WebServer webServer = context.getWebServer();
            if (webServer != null) {
                webServer.shutDownGracefully(result -> {
                    switch (result) {
                        case IDLE -> System.out.println("Server shutdown gracefully - was idle");
                        case REQUESTS_ACTIVE -> System.out.println("Server shutdown with active requests");
                        case IMMEDIATE -> System.out.println("Server shutdown immediately");
                    }
                });
            }
        };
    }
}

Complete Integration Example

Here's a comprehensive example that demonstrates servlet support, error handling, and both servlet and reactive contexts:

@SpringBootApplication
public class WebSupportDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebSupportDemoApplication.class, args);
    }
}

// Servlet Registration
@Configuration
public class ServletConfiguration {

    @Bean
    public ServletRegistrationBean<ApiServlet> apiServlet() {
        ServletRegistrationBean<ApiServlet> bean =
            new ServletRegistrationBean<>(new ApiServlet(), "/api/v1/*");
        bean.setLoadOnStartup(1);
        bean.addInitParameter("api-version", "1.0");
        return bean;
    }

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> bean =
            new FilterRegistrationBean<>(new CorsFilter());
        bean.addUrlPatterns("/*");
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }

    @Bean
    public ServletListenerRegistrationBean<ApplicationListener> appListener() {
        return new ServletListenerRegistrationBean<>(
            new ApplicationListener()
        );
    }
}

// Error Page Configuration
@Configuration
public class ErrorConfiguration {

    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return registry -> {
            registry.addErrorPages(
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
                new ErrorPage(IllegalArgumentException.class, "/error/bad-request"),
                new ErrorPage("/error")  // Global error page
            );
        };
    }
}

@Controller
@RequestMapping("/error")
public class CustomErrorController {

    @RequestMapping("/404")
    public String notFound(Model model, HttpServletRequest request) {
        model.addAttribute("path", request.getAttribute(
            ErrorPageFilter.ERROR_REQUEST_URI));
        return "error/404";
    }

    @RequestMapping("/500")
    public String serverError(Model model) {
        return "error/500";
    }

    @RequestMapping
    public String generalError(Model model, HttpServletRequest request) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults()
            .including(Include.MESSAGE, Include.EXCEPTION);

        model.addAttribute("options", options);
        return "error/general";
    }
}

// Reactive Web Configuration
@Configuration
@EnableWebFlux
public class ReactiveWebConfiguration {

    @Bean
    public RouterFunction<ServerResponse> userRoutes(UserHandler handler) {
        return RouterFunctions.route()
            .GET("/users", handler::list)
            .GET("/users/{id}", handler::get)
            .POST("/users", handler::create)
            .PUT("/users/{id}", handler::update)
            .DELETE("/users/{id}", handler::delete)
            .build();
    }

    @Bean
    public WebFilter loggingFilter() {
        return (exchange, chain) -> {
            System.out.println("Request: " + exchange.getRequest().getPath());
            return chain.filter(exchange)
                .doOnSuccess(v -> System.out.println("Response sent"));
        };
    }
}

@Component
public class UserHandler {

    private final UserRepository repository;

    public UserHandler(UserRepository repository) {
        this.repository = repository;
    }

    public Mono<ServerResponse> list(ServerRequest request) {
        return ServerResponse.ok()
            .contentType(MediaType.APPLICATION_JSON)
            .body(repository.findAll(), User.class);
    }

    public Mono<ServerResponse> get(ServerRequest request) {
        String id = request.pathVariable("id");
        return repository.findById(id)
            .flatMap(user -> ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(user))
            .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> create(ServerRequest request) {
        return request.bodyToMono(User.class)
            .flatMap(repository::save)
            .flatMap(user -> ServerResponse.created(
                URI.create("/users/" + user.getId()))
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(user));
    }
}

Web Server Context and Events

Spring Boot provides specialized application context implementations and events for web server lifecycle management.

WebServerApplicationContext

Interface to be implemented by application contexts that create and manage the lifecycle of an embedded WebServer.

package org.springframework.boot.web.server.context;

/**
 * Interface to be implemented by application contexts that create and manage
 * the lifecycle of an embedded WebServer.
 *
 * @since 4.0.0
 */
public interface WebServerApplicationContext extends ApplicationContext {

    /**
     * SmartLifecycle phase in which graceful shutdown of the web server is
     * performed.
     *
     * @since 4.0.0
     */
    int GRACEFUL_SHUTDOWN_PHASE = SmartLifecycle.DEFAULT_PHASE - 1024;

    /**
     * SmartLifecycle phase in which starting and stopping of the web server
     * is performed.
     */
    int START_STOP_LIFECYCLE_PHASE = GRACEFUL_SHUTDOWN_PHASE - 1024;

    /**
     * Returns the WebServer that was created by the context or null if the
     * server has not yet been created.
     *
     * @return the web server
     */
    WebServer getWebServer();

    /**
     * Returns the namespace of the web server application context or null if
     * no namespace has been set. Used for disambiguation when multiple web
     * servers are running in the same application.
     *
     * @return the server namespace
     */
    String getServerNamespace();

    /**
     * Returns true if the specified context is a WebServerApplicationContext
     * with a matching server namespace.
     *
     * @param context the context to check
     * @param serverNamespace the server namespace to match against
     * @return true if the server namespace of the context matches
     */
    static boolean hasServerNamespace(ApplicationContext context,
                                      String serverNamespace) {
        return (context instanceof WebServerApplicationContext webServerApplicationContext)
                && ObjectUtils.nullSafeEquals(
                    webServerApplicationContext.getServerNamespace(),
                    serverNamespace);
    }

    /**
     * Returns the server namespace if the specified context is a
     * WebServerApplicationContext.
     *
     * @param context the context
     * @return the server namespace or null if the context is not a
     *         WebServerApplicationContext
     */
    static String getServerNamespace(ApplicationContext context) {
        return (context instanceof WebServerApplicationContext configurableContext)
                ? configurableContext.getServerNamespace() : null;
    }
}

ConfigurableWebServerApplicationContext

SPI interface to be implemented by most if not all web server application contexts.

package org.springframework.boot.web.server.context;

/**
 * SPI interface to be implemented by most if not all web server application
 * contexts. Provides facilities to configure the context, in addition to the
 * methods in the WebServerApplicationContext interface.
 *
 * @since 4.0.0
 */
public interface ConfigurableWebServerApplicationContext
        extends ConfigurableApplicationContext, WebServerApplicationContext {

    /**
     * Set the server namespace of the context.
     *
     * @param serverNamespace the server namespace
     */
    void setServerNamespace(String serverNamespace);
}

WebServerInitializedEvent

Event to be published when the WebServer is ready.

package org.springframework.boot.web.server.context;

/**
 * Event to be published when the WebServer is ready. Useful for obtaining the
 * local port of a running server.
 *
 * @since 4.0.0
 */
public abstract class WebServerInitializedEvent extends ApplicationEvent {

    /**
     * Creates a new WebServerInitializedEvent.
     *
     * @param webServer the web server
     */
    protected WebServerInitializedEvent(WebServer webServer) { }

    /**
     * Access the WebServer.
     *
     * @return the embedded web server
     */
    public WebServer getWebServer() {
        return getSource();
    }

    /**
     * Access the application context that the server was created in.
     *
     * @return the applicationContext that the server was created from
     */
    public abstract WebServerApplicationContext getApplicationContext();

    /**
     * Access the source of the event (an WebServer).
     *
     * @return the embedded web server
     */
    @Override
    public WebServer getSource() {
        return (WebServer) super.getSource();
    }
}

Usage Example:

@Component
public class WebServerPortListener {

    @EventListener
    public void onApplicationEvent(WebServerInitializedEvent event) {
        int port = event.getWebServer().getPort();
        System.out.println("Web server started on port: " + port);
    }
}

Common Patterns

Pattern 1: Custom Servlet and Filter Registration with Security

Register custom servlets and filters with proper URL mapping and security configuration.

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.util.EnumSet;

@Configuration
public class ServletConfiguration {

    // Register custom servlet
    @Bean
    public ServletRegistrationBean<CustomServlet> customServlet() {
        ServletRegistrationBean<CustomServlet> registration =
            new ServletRegistrationBean<>(new CustomServlet(), "/api/custom/*");

        // Set load-on-startup priority
        registration.setLoadOnStartup(1);

        // Add initialization parameters
        registration.addInitParameter("configLocation", "classpath:custom-config.xml");
        registration.addInitParameter("debug", "true");

        return registration;
    }

    // Register authentication filter
    @Bean
    public FilterRegistrationBean<AuthenticationFilter> authFilter() {
        FilterRegistrationBean<AuthenticationFilter> registration =
            new FilterRegistrationBean<>(new AuthenticationFilter());

        // Apply to specific URL patterns
        registration.addUrlPatterns("/api/*", "/admin/*");

        // Set dispatcher types
        registration.setDispatcherTypes(
            EnumSet.of(
                DispatcherType.REQUEST,
                DispatcherType.FORWARD,
                DispatcherType.ERROR
            )
        );

        // Set filter order (lower values execute first)
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);

        return registration;
    }

    // Register CORS filter
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> registration =
            new FilterRegistrationBean<>(new CorsFilter());

        // Apply to all paths
        registration.addUrlPatterns("/*");

        // Execute before authentication
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE - 1);

        return registration;
    }

    // Register session listener
    @Bean
    public ServletListenerRegistrationBean<SessionListener> sessionListener() {
        return new ServletListenerRegistrationBean<>(new SessionListener());
    }
}

// Custom servlet implementation
public class CustomServlet extends HttpServlet {

    private String configLocation;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.configLocation = config.getInitParameter("configLocation");
        System.out.println("CustomServlet initialized with config: " + configLocation);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("application/json");
        resp.getWriter().write("{\"status\":\"ok\",\"config\":\"" + configLocation + "\"}");
    }

    @Override
    public void destroy() {
        System.out.println("CustomServlet destroyed");
    }
}

// Authentication filter
public class AuthenticationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String token = httpRequest.getHeader("Authorization");

        if (token == null || !validateToken(token)) {
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
            return;
        }

        // Add user info to request attributes
        httpRequest.setAttribute("userId", extractUserId(token));

        chain.doFilter(request, response);
    }

    private boolean validateToken(String token) {
        return token != null && token.startsWith("Bearer ");
    }

    private String extractUserId(String token) {
        return "user123"; // Extract from JWT
    }
}

// CORS filter
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");

        chain.doFilter(request, response);
    }
}

// Session listener
public class SessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("Session created: " + se.getSession().getId());
        se.getSession().setMaxInactiveInterval(1800); // 30 minutes
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Session destroyed: " + se.getSession().getId());
    }
}

Use Cases:

  • Custom API endpoints alongside Spring MVC
  • Legacy servlet integration
  • Fine-grained filter ordering and configuration
  • Session management customization

Pattern 2: Custom Error Pages with Exception Mapping

Implement comprehensive error handling with custom error pages.

import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.WebRequest;
import java.util.Map;

@Configuration
public class ErrorPageConfiguration {

    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return registry -> {
            // Register status code error pages
            registry.addErrorPages(
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.FORBIDDEN, "/error/403"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
                new ErrorPage(HttpStatus.SERVICE_UNAVAILABLE, "/error/503")
            );

            // Register exception-based error pages
            registry.addErrorPages(
                new ErrorPage(IllegalArgumentException.class, "/error/badrequest"),
                new ErrorPage(AccessDeniedException.class, "/error/accessdenied"),
                new ErrorPage(DataAccessException.class, "/error/database")
            );

            // Generic error page for uncaught exceptions
            registry.addErrorPages(new ErrorPage("/error/general"));
        };
    }
}

@Controller
public class CustomErrorController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    public CustomErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping("/error/404")
    public ResponseEntity<ErrorResponse> handle404(WebRequest webRequest) {
        Map<String, Object> attributes = getErrorAttributes(webRequest);

        ErrorResponse error = new ErrorResponse(
            "NOT_FOUND",
            "The requested resource was not found",
            (String) attributes.get("path")
        );

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @RequestMapping("/error/403")
    public ResponseEntity<ErrorResponse> handle403(WebRequest webRequest) {
        Map<String, Object> attributes = getErrorAttributes(webRequest);

        ErrorResponse error = new ErrorResponse(
            "FORBIDDEN",
            "You don't have permission to access this resource",
            (String) attributes.get("path")
        );

        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error);
    }

    @RequestMapping("/error/500")
    public ResponseEntity<ErrorResponse> handle500(WebRequest webRequest) {
        Map<String, Object> attributes = getErrorAttributes(webRequest);

        ErrorResponse error = new ErrorResponse(
            "INTERNAL_SERVER_ERROR",
            "An internal server error occurred",
            (String) attributes.get("path")
        );

        // Log the exception
        Throwable exception = errorAttributes.getError(webRequest);
        if (exception != null) {
            log.error("Internal server error", exception);
        }

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }

    @RequestMapping("/error/badrequest")
    public ResponseEntity<ErrorResponse> handleBadRequest(WebRequest webRequest) {
        Map<String, Object> attributes = getErrorAttributes(webRequest);
        Throwable exception = errorAttributes.getError(webRequest);

        ErrorResponse error = new ErrorResponse(
            "BAD_REQUEST",
            exception != null ? exception.getMessage() : "Invalid request",
            (String) attributes.get("path")
        );

        return ResponseEntity.badRequest().body(error);
    }

    @RequestMapping("/error/general")
    public ResponseEntity<ErrorResponse> handleGeneral(WebRequest webRequest) {
        Map<String, Object> attributes = getErrorAttributes(webRequest);
        Integer status = (Integer) attributes.get("status");

        ErrorResponse error = new ErrorResponse(
            "ERROR",
            "An error occurred while processing your request",
            (String) attributes.get("path")
        );

        return ResponseEntity.status(status != null ? status : 500).body(error);
    }

    private Map<String, Object> getErrorAttributes(WebRequest webRequest) {
        return errorAttributes.getErrorAttributes(webRequest,
            ErrorAttributeOptions.of(
                ErrorAttributeOptions.Include.MESSAGE,
                ErrorAttributeOptions.Include.BINDING_ERRORS
            ));
    }
}

// Error response DTO
public record ErrorResponse(
    String code,
    String message,
    String path,
    long timestamp
) {
    public ErrorResponse(String code, String message, String path) {
        this(code, message, path, System.currentTimeMillis());
    }
}

Use Cases:

  • Consistent error response format across application
  • Custom error pages for different HTTP status codes
  • Exception-specific error handling
  • Error logging and monitoring integration

Pattern 3: Embedded Server Customization for Production

Configure embedded servers with production-ready settings.

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.Http2;
import org.springframework.boot.web.server.Ssl;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import java.io.File;
import java.time.Duration;

@Configuration
public class EmbeddedServerConfiguration {

    // General server configuration
    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerCustomizer() {
        return factory -> {
            // Port configuration
            factory.setPort(8443);

            // Context path
            factory.setContextPath("/api");

            // Session timeout
            factory.getSession().setTimeout(Duration.ofMinutes(30));
            factory.getSession().getCookie().setHttpOnly(true);
            factory.getSession().getCookie().setSecure(true);

            // Compression
            Compression compression = new Compression();
            compression.setEnabled(true);
            compression.setMinResponseSize(1024);
            compression.setMimeTypes(new String[]{
                "text/html", "text/xml", "text/plain",
                "text/css", "application/javascript",
                "application/json", "application/xml"
            });
            factory.setCompression(compression);

            // HTTP/2 support
            Http2 http2 = new Http2();
            http2.setEnabled(true);
            factory.setHttp2(http2);

            // SSL configuration
            Ssl ssl = new Ssl();
            ssl.setEnabled(true);
            ssl.setKeyStore("classpath:keystore.p12");
            ssl.setKeyStorePassword("changeit");
            ssl.setKeyStoreType("PKCS12");
            ssl.setKeyAlias("tomcat");
            factory.setSsl(ssl);
        };
    }

    // Tomcat-specific configuration
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
        return factory -> {
            // Connection pool settings
            factory.addConnectorCustomizers(connector -> {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();

                // Thread pool
                protocol.setMaxThreads(200);
                protocol.setMinSpareThreads(10);

                // Connection settings
                protocol.setMaxConnections(10000);
                protocol.setAcceptCount(100);

                // Timeouts
                protocol.setConnectionTimeout(20000);
                protocol.setKeepAliveTimeout(60000);

                // Compression (if not set globally)
                protocol.setCompression("on");
                protocol.setCompressionMinSize(1024);
            });

            // Add AJP connector for load balancer
            factory.addAdditionalTomcatConnectors(createAjpConnector());

            // Access log
            factory.addContextCustomizers(context -> {
                context.getParent().getPipeline().addValve(
                    new org.apache.catalina.valves.AccessLogValve()
                );
            });
        };
    }

    private Connector createAjpConnector() {
        Connector connector = new Connector("AJP/1.3");
        connector.setPort(8009);
        connector.setSecure(false);
        connector.setAllowTrace(false);
        connector.setScheme("http");
        return connector;
    }

    // Undertow-specific configuration
    @Bean
    public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowCustomizer() {
        return factory -> {
            // Buffer sizes
            factory.setBufferSize(16384);
            factory.setIoThreads(Runtime.getRuntime().availableProcessors() * 2);
            factory.setWorkerThreads(200);

            // Direct buffers
            factory.setDirectBuffers(true);

            // Undertow options
            factory.addBuilderCustomizers(builder -> {
                builder.setServerOption(
                    io.undertow.UndertowOptions.ENABLE_HTTP2, true
                );
                builder.setServerOption(
                    io.undertow.UndertowOptions.MAX_ENTITY_SIZE, 100L * 1024 * 1024
                );
            });
        };
    }
}

application.yml:

server:
  port: 8443
  shutdown: graceful
  max-http-request-header-size: 16KB

  tomcat:
    threads:
      max: 200
      min-spare: 10
    max-connections: 10000
    accept-count: 100
    connection-timeout: 20s

  compression:
    enabled: true
    min-response-size: 1KB
    mime-types:
      - text/html
      - text/xml
      - text/plain
      - text/css
      - application/javascript
      - application/json
      - application/xml

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

Use Cases:

  • Production-ready server configuration
  • Performance tuning for high traffic
  • SSL/TLS configuration
  • Load balancer integration

Pattern 4: Graceful Shutdown with Active Request Tracking

Implement graceful shutdown with monitoring of active requests.

import org.springframework.boot.web.server.GracefulShutdownCallback;
import org.springframework.boot.web.server.GracefulShutdownResult;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

// Track active requests
@Component
public class ActiveRequestTracker extends OncePerRequestFilter {

    private final AtomicInteger activeRequests = new AtomicInteger(0);

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                   HttpServletResponse response,
                                   FilterChain filterChain)
            throws ServletException, IOException {

        activeRequests.incrementAndGet();
        try {
            filterChain.doFilter(request, response);
        } finally {
            activeRequests.decrementAndGet();
        }
    }

    public int getActiveRequests() {
        return activeRequests.get();
    }
}

// Graceful shutdown manager
@Component
public class GracefulShutdownManager implements ApplicationListener<ContextClosedEvent> {

    private static final Logger log = LoggerFactory.getLogger(GracefulShutdownManager.class);

    private final ActiveRequestTracker requestTracker;
    private final WebServer webServer;

    public GracefulShutdownManager(ActiveRequestTracker requestTracker,
                                  WebServerApplicationContext context) {
        this.requestTracker = requestTracker;
        this.webServer = context.getWebServer();
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info("Initiating graceful shutdown");

        // Stop accepting new requests
        webServer.shutDownGracefully(result -> {
            log.info("Graceful shutdown completed with result: {}", result);

            if (result == GracefulShutdownResult.REQUESTS_ACTIVE) {
                int active = requestTracker.getActiveRequests();
                log.warn("{} requests were still active during shutdown", active);
            }
        });

        // Monitor active requests
        monitorActiveRequests();
    }

    private void monitorActiveRequests() {
        int checkCount = 0;
        int maxChecks = 30; // 30 seconds max wait

        while (checkCount < maxChecks) {
            int active = requestTracker.getActiveRequests();

            if (active == 0) {
                log.info("All requests completed");
                break;
            }

            log.info("Waiting for {} active requests to complete", active);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }

            checkCount++;
        }

        if (requestTracker.getActiveRequests() > 0) {
            log.warn("Shutdown timeout reached with {} active requests",
                requestTracker.getActiveRequests());
        }
    }
}

// Health check endpoint that considers shutdown state
@RestController
public class HealthController {

    private volatile boolean shuttingDown = false;

    @EventListener(ContextClosedEvent.class)
    public void onShutdown() {
        shuttingDown = true;
    }

    @GetMapping("/health")
    public ResponseEntity<Map<String, String>> health() {
        if (shuttingDown) {
            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                .body(Map.of("status", "SHUTTING_DOWN"));
        }

        return ResponseEntity.ok(Map.of("status", "UP"));
    }

    @GetMapping("/health/ready")
    public ResponseEntity<Map<String, String>> readiness() {
        if (shuttingDown) {
            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                .body(Map.of("status", "NOT_READY"));
        }

        return ResponseEntity.ok(Map.of("status", "READY"));
    }
}

Use Cases:

  • Zero-downtime deployments
  • Kubernetes rolling updates
  • Load balancer health check integration
  • Request completion monitoring

Pattern 5: Reactive WebFlux Server Configuration

Configure WebFlux reactive server with optimized settings.

import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import reactor.netty.http.server.HttpServer;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.resources.LoopResources;
import java.time.Duration;

@Configuration
public class ReactiveServerConfiguration {

    @Bean
    public ReactorResourceFactory reactorResourceFactory() {
        ReactorResourceFactory factory = new ReactorResourceFactory();

        // Connection provider settings
        ConnectionProvider provider = ConnectionProvider.builder("custom")
            .maxConnections(500)
            .maxIdleTime(Duration.ofSeconds(20))
            .maxLifeTime(Duration.ofSeconds(60))
            .pendingAcquireTimeout(Duration.ofSeconds(45))
            .evictInBackground(Duration.ofSeconds(120))
            .build();

        factory.setConnectionProvider(provider);

        // Event loop settings
        LoopResources loopResources = LoopResources.create(
            "event-loop",
            Runtime.getRuntime().availableProcessors(),
            true
        );

        factory.setLoopResources(loopResources);
        factory.setUseGlobalResources(false);

        return factory;
    }

    @Bean
    public WebServerFactoryCustomizer<NettyReactiveWebServerFactory> nettyCustomizer(
            ReactorResourceFactory resourceFactory) {

        return factory -> {
            factory.setResourceFactory(resourceFactory);

            // Netty-specific customization
            factory.addServerCustomizers(httpServer ->
                httpServer
                    .idleTimeout(Duration.ofSeconds(30))
                    .maxKeepAliveRequests(100)
                    .compress(true)
                    .accessLog(true)
                    .http2Settings(spec ->
                        spec.maxConcurrentStreams(100)
                            .initialWindowSize(65535)
                    )
            );
        };
    }

    // Custom error handler for WebFlux
    @Bean
    public WebExceptionHandler customWebExceptionHandler() {
        return (exchange, ex) -> {
            log.error("Unhandled error in reactive request", ex);

            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

            ErrorResponse error = new ErrorResponse(
                "INTERNAL_ERROR",
                "An unexpected error occurred",
                exchange.getRequest().getPath().value()
            );

            DataBuffer buffer = exchange.getResponse()
                .bufferFactory()
                .wrap(new ObjectMapper().writeValueAsBytes(error));

            return exchange.getResponse().writeWith(Mono.just(buffer));
        };
    }
}

// Reactive request tracking filter
@Component
public class ReactiveRequestTrackingFilter implements WebFilter {

    private static final Logger log = LoggerFactory.getLogger(ReactiveRequestTrackingFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        long startTime = System.currentTimeMillis();
        String requestId = UUID.randomUUID().toString();

        return chain.filter(exchange)
            .contextWrite(Context.of("requestId", requestId))
            .doFinally(signalType -> {
                long duration = System.currentTimeMillis() - startTime;
                log.info("Request {} completed in {}ms with signal: {}",
                    requestId, duration, signalType);
            });
    }
}

application.yml:

spring:
  webflux:
    base-path: /api

  reactor:
    context-propagation: auto

server:
  netty:
    connection-timeout: 20s
    idle-timeout: 30s
  max-http-request-header-size: 16KB

Use Cases:

  • High-concurrency reactive applications
  • Streaming data processing
  • WebSocket servers
  • Non-blocking I/O requirements

Best Practices

Server Configuration

  1. Use Graceful Shutdown: Always enable graceful shutdown in production
  2. Configure Thread Pools: Tune thread pools based on load testing results
  3. Enable Compression: Enable response compression for text-based content
  4. Set Appropriate Timeouts: Configure connection and read timeouts
  5. Use HTTP/2: Enable HTTP/2 for better performance
  6. Configure SSL Properly: Use strong ciphers and protocols (TLS 1.2+)
  7. Limit Request Sizes: Set maximum request header and body sizes
  8. Enable Access Logs: Configure access logging for monitoring

Error Handling

  1. Implement Custom Error Pages: Provide user-friendly error pages
  2. Map Exceptions to Status Codes: Use ErrorPageRegistrar for exception mapping
  3. Log Errors Appropriately: Log internal errors, don't expose to clients
  4. Return Consistent Error Format: Use standardized error response structure
  5. Include Request Context: Add correlation IDs for error tracking
  6. Handle All Error Scenarios: 4xx client errors, 5xx server errors
  7. Test Error Handling: Verify error pages and exception mapping

Performance Optimization

  1. Connection Pooling: Configure appropriate connection pool sizes
  2. Keep-Alive Settings: Enable keep-alive with reasonable timeouts
  3. Compression: Enable for text content, consider trade-offs
  4. Async Processing: Use async servlets or reactive for long-running operations
  5. Resource Limits: Set memory and thread limits appropriately
  6. Monitor Metrics: Track request rates, response times, error rates

Security Best Practices

  1. HTTPS Only in Production: Enforce SSL/TLS in production
  2. Secure Session Cookies: Set HttpOnly and Secure flags
  3. CSRF Protection: Enable CSRF tokens for state-changing operations
  4. Security Headers: Add security headers (HSTS, X-Frame-Options, etc.)
  5. Request Size Limits: Prevent DoS with size limits
  6. Filter Ordering: Ensure security filters execute first
  7. Sanitize Error Messages: Don't expose stack traces to clients

Testing Web Configuration

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class WebConfigurationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void shouldReturnCustomErrorPage() {
        ResponseEntity<String> response =
            restTemplate.getForEntity("http://localhost:" + port + "/nonexistent",
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
        assertThat(response.getBody()).contains("NOT_FOUND");
    }

    @Test
    void shouldApplyCompressionToTextContent() {
        HttpHeaders headers = new HttpHeaders();
        headers.setAcceptEncoding(List.of(ContentCodingType.GZIP));

        ResponseEntity<String> response = restTemplate.exchange(
            "http://localhost:" + port + "/api/data",
            HttpMethod.GET,
            new HttpEntity<>(headers),
            String.class
        );

        assertThat(response.getHeaders().getFirst("Content-Encoding"))
            .isEqualTo("gzip");
    }
}

Common Pitfalls to Avoid

  1. Don't ignore graceful shutdown - Can cause in-flight request failures
  2. Don't use default thread pool sizes - Tune based on actual load
  3. Don't expose internal errors - Sanitize error messages for external clients
  4. Don't forget filter ordering - Security filters must execute first
  5. Don't skip SSL in production - Always use HTTPS in production
  6. Don't ignore connection limits - Set appropriate max connections
  7. Don't forget to configure timeouts - Prevents hanging connections
  8. Don't mix servlet and reactive - Choose one programming model
  9. Don't skip compression configuration - Can significantly reduce bandwidth
  10. Don't forget health check endpoints - Essential for load balancer integration

Summary

Spring Boot's web application support provides:

  1. Servlet Support: Comprehensive APIs for registering servlets, filters, and listeners programmatically

    • ServletRegistrationBean - Register servlets with URL mappings and initialization parameters
    • FilterRegistrationBean and AbstractFilterRegistrationBean - Register filters with URL patterns, servlet mappings, and dispatcher types
    • ServletListenerRegistrationBean - Register event listeners for servlet context, session, and request events
    • DelegatingFilterProxyRegistrationBean - Register filters that delegate to Spring-managed beans with lazy initialization support
  2. Servlet Context Support: Specialized contexts and environments for servlet-based applications, including WAR deployment support

    • AnnotationConfigServletWebApplicationContext - Annotation-based servlet web application context
    • ApplicationServletEnvironment - Standard servlet environment for Spring Boot applications
    • SpringBootServletInitializer - Support for traditional WAR deployment with servlet containers
  3. Reactive Support: Full reactive web application support with specialized contexts and environments

    • ReactiveWebApplicationContext - Marker interface for reactive web contexts
    • AnnotationConfigReactiveWebApplicationContext - Annotation-based reactive web application context
    • GenericReactiveWebApplicationContext - Generic reactive web application context
    • StandardReactiveWebEnvironment - Standard environment for reactive applications
  4. Error Page Support: Flexible error page registration and handling for both servlet and reactive applications

    • ErrorPage - Simple server-independent abstraction for error pages
    • ErrorPageRegistry - Interface for registries that hold error pages
    • ErrorPageRegistrar - Interface for types that register error pages
    • ErrorPageFilter - Filter that provides error page handling for non-embedded applications
    • ErrorAttributeOptions - Options controlling the contents of error attributes
  5. Web Server Factory and Customization: Complete API for creating and customizing embedded web servers

    • WebServer - Core interface representing a fully configured web server with lifecycle management
    • WebServerFactory - Base interface for web server factories
    • ConfigurableWebServerFactory - Configurable factory with common server configuration options
    • ServletWebServerFactory and ConfigurableServletWebServerFactory - Factories for servlet-based web servers
    • ReactiveWebServerFactory and ConfigurableReactiveWebServerFactory - Factories for reactive web servers
    • WebServerFactoryCustomizer - Strategy interface for customizing web server factories
    • GracefulShutdownCallback, GracefulShutdownResult, and Shutdown - Support for graceful server shutdown
  6. Web Server Context and Lifecycle: Specialized application contexts and events for web server lifecycle management

    • WebServerApplicationContext - Interface for contexts that create and manage embedded web servers
    • ConfigurableWebServerApplicationContext - Configurable web server application context with namespace support
    • WebServerInitializedEvent - Event published when the web server is ready

These components work together to provide a complete, production-ready web application framework that supports both traditional servlet-based and modern reactive architectures. The framework provides fine-grained control over server configuration, error handling, graceful shutdown, and lifecycle management while maintaining a simple and consistent API across different server types.