CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-actuator-autoconfigure

Spring Boot Actuator AutoConfigure module providing production-ready features to Spring Boot applications through auto-configuration

Pending
Overview
Eval results
Files

web-endpoints.mddocs/

Web Endpoint Exposure

Configuration for HTTP exposure of Spring Boot Actuator endpoints, including path mapping, filtering, CORS, and discovery.

Quick Reference

Essential Configuration

# Expose endpoints
management.endpoints.web.exposure.include=health,info,metrics
management.endpoints.web.exposure.exclude=shutdown

# Base path
management.endpoints.web.base-path=/actuator

# Path mappings
management.endpoints.web.path-mapping.health=healthcheck

# CORS
management.endpoints.web.cors.allowed-origins=https://example.com
management.endpoints.web.cors.allowed-methods=GET,POST

URL Structure

http://<host>:<port>/<base-path>/<endpoint-id-or-mapping>

Examples:
- http://localhost:8080/actuator/health
- http://localhost:8080/actuator/healthcheck (with path mapping)
- http://localhost:8080/management/health (custom base path)

API Reference

WebEndpointAutoConfiguration

@AutoConfiguration
@ConditionalOnWebApplication
@EnableConfigurationProperties(WebEndpointProperties.class)
public final class WebEndpointAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(WebEndpointsSupplier.class)
    WebEndpointDiscoverer webEndpointDiscoverer(
        ParameterValueMapper parameterValueMapper,
        EndpointMediaTypes endpointMediaTypes,
        ObjectProvider<PathMapper> endpointPathMappers,
        ObjectProvider<AdditionalPathsMapper> additionalPathsMappers,
        ObjectProvider<OperationInvokerAdvisor> invokerAdvisors,
        ObjectProvider<EndpointFilter<ExposableWebEndpoint>> endpointFilters,
        ObjectProvider<OperationFilter<WebOperation>> operationFilters
    );

    @Bean
    PathMapper webEndpointPathMapper();

    @Bean
    @ConditionalOnMissingBean
    EndpointMediaTypes endpointMediaTypes();

    @Bean
    @ConditionalOnMissingBean
    PathMappedEndpoints pathMappedEndpoints(Collection<EndpointsSupplier<?>> endpointSuppliers);

    @Bean
    IncludeExcludeEndpointFilter<ExposableWebEndpoint> webExposeExcludePropertyEndpointFilter();

    /**
     * Creates controller endpoint discoverer (DEPRECATED)
     * @deprecated since 3.3.0, scheduled for removal in a future release
     * Controller endpoints are deprecated in favor of @Endpoint with web extensions
     */
    @Bean
    @ConditionalOnMissingBean
    @Deprecated(since = "3.3.0", forRemoval = true)
    ControllerEndpointDiscoverer controllerEndpointDiscoverer(
        ObjectProvider<PathMapper> endpointPathMappers,
        ObjectProvider<Collection<EndpointFilter<ExposableControllerEndpoint>>> filters
    );

    /**
     * Creates include/exclude filter for controller endpoints (DEPRECATED)
     * @deprecated since 3.3.0, scheduled for removal in a future release
     */
    @Bean
    @Deprecated(since = "3.3.0", forRemoval = true)
    IncludeExcludeEndpointFilter<ExposableControllerEndpoint> controllerExposeExcludePropertyEndpointFilter();

    /**
     * Creates operation filter based on endpoint access properties
     * Filters operations based on access levels (UNRESTRICTED, READ_ONLY, NONE)
     * @param endpointAccessResolver Access resolver from properties
     * @return Operation filter that enforces access restrictions
     * @since 3.4.0
     */
    @Bean
    OperationFilter<WebOperation> webAccessPropertiesOperationFilter(EndpointAccessResolver endpointAccessResolver);

    /**
     * Servlet-specific endpoint configuration
     * Only active for servlet web applications
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    static class WebEndpointServletConfiguration {
        /**
         * Creates servlet endpoint discoverer (DEPRECATED)
         * @deprecated since 3.3.0, scheduled for removal in a future release
         * Servlet endpoints are deprecated in favor of @Endpoint with web extensions
         */
        @Bean
        @ConditionalOnMissingBean
        @Deprecated(since = "3.3.0", forRemoval = true)
        ServletEndpointDiscoverer servletEndpointDiscoverer(
            ApplicationContext applicationContext,
            ObjectProvider<PathMapper> endpointPathMappers,
            ObjectProvider<EndpointFilter<ExposableServletEndpoint>> filters
        );
    }
}

WebEndpointProperties

@ConfigurationProperties("management.endpoints.web")
public class WebEndpointProperties {

    private String basePath = "/actuator";                    // Base path
    private Map<String, String> pathMapping = new LinkedHashMap<>();  // Custom paths
    private Exposure exposure = new Exposure();               // Include/exclude
    private Discovery discovery = new Discovery();            // Discovery page

    public static class Exposure {
        private Set<String> include = new LinkedHashSet<>();  // Default: ["health"]
        private Set<String> exclude = new LinkedHashSet<>();  // Default: empty
    }

    public static class Discovery {
        private boolean enabled = true;                       // Discovery page enabled
    }
}

Path Mapping

Default Mappings

Endpoint IDDefault PathConfigurable Via
health/actuator/healthmanagement.endpoints.web.path-mapping.health
info/actuator/infomanagement.endpoints.web.path-mapping.info
metrics/actuator/metricsmanagement.endpoints.web.path-mapping.metrics

Custom Path Mapping Example

management.endpoints.web.base-path=/management
management.endpoints.web.path-mapping.health=status
management.endpoints.web.path-mapping.info=about
management.endpoints.web.path-mapping.metrics=stats

Result:

  • /management/status (was /actuator/health)
  • /management/about (was /actuator/info)
  • /management/stats (was /actuator/metrics)

Programmatic Path Mapping

@Bean
public PathMapper customPathMapper() {
    return endpointId -> {
        String id = endpointId.toString();
        return switch (id) {
            case "health" -> "healthcheck";
            case "info" -> "information";
            default -> id;
        };
    };
}

CORS Configuration

Properties

# Allowed origins (exact match)
management.endpoints.web.cors.allowed-origins=https://app.example.com,https://admin.example.com

# Allowed origin patterns (wildcards)
management.endpoints.web.cors.allowed-origin-patterns=https://*.example.com

# Methods
management.endpoints.web.cors.allowed-methods=GET,POST,PUT,DELETE

# Headers
management.endpoints.web.cors.allowed-headers=Authorization,Content-Type

# Expose headers
management.endpoints.web.cors.exposed-headers=X-Custom-Header

# Credentials
management.endpoints.web.cors.allow-credentials=true

# Cache duration
management.endpoints.web.cors.max-age=3600

CORS Configuration Patterns

Development (Permissive):

management.endpoints.web.cors.allowed-origin-patterns=*
management.endpoints.web.cors.allowed-methods=*
management.endpoints.web.cors.allowed-headers=*
management.endpoints.web.cors.allow-credentials=true

Production (Restrictive):

management.endpoints.web.cors.allowed-origins=https://app.example.com
management.endpoints.web.cors.allowed-methods=GET,POST
management.endpoints.web.cors.allowed-headers=Authorization,Content-Type
management.endpoints.web.cors.allow-credentials=true
management.endpoints.web.cors.max-age=3600

Endpoint Discovery

Discovery Page

URL: <base-path> (e.g., /actuator)

Response:

{
  "_links": {
    "self": {"href": "http://localhost:8080/actuator"},
    "health": {"href": "http://localhost:8080/actuator/health"},
    "info": {"href": "http://localhost:8080/actuator/info"},
    "metrics": {"href": "http://localhost:8080/actuator/metrics"}
  }
}

Disable Discovery:

management.endpoints.web.discovery.enabled=false

Endpoint Filtering

# Include all
management.endpoints.web.exposure.include=*

# Include specific
management.endpoints.web.exposure.include=health,info,metrics

# Exclude (takes precedence)
management.endpoints.web.exposure.exclude=shutdown,heapdump

Web Operation Predicates

/**
 * Request predicate for web operations
 * Defines the HTTP request characteristics an operation can handle
 */
public class WebOperationRequestPredicate {
    private final String path;                        // Operation path
    private final WebEndpointHttpMethod httpMethod;   // GET, POST, DELETE
    private final Collection<String> consumes;        // Content-Type
    private final Collection<String> produces;        // Accept

    /**
     * Gets the operation path (relative to endpoint root path)
     * @return The path (e.g., "", "/{name}")
     */
    public String getPath();

    /**
     * Gets the HTTP method for this operation
     * @return The HTTP method
     */
    public WebEndpointHttpMethod getHttpMethod();

    /**
     * Gets the media types this operation can consume
     * @return Collection of consumable media types
     */
    public Collection<String> getConsumes();

    /**
     * Gets the media types this operation can produce
     * @return Collection of producible media types
     */
    public Collection<String> getProduces();
}

/**
 * HTTP methods supported by web endpoint operations
 */
public enum WebEndpointHttpMethod {
    GET,     // Read operation
    POST,    // Write operation
    DELETE   // Delete operation
}

Media Types

Default Produced: application/vnd.spring-boot.actuator.v3+json, application/json

Default Consumed: application/vnd.spring-boot.actuator.v3+json, application/json

Customization Examples

Custom Endpoint Filter

@Bean
public EndpointFilter<ExposableWebEndpoint> customWebEndpointFilter() {
    return endpoint -> {
        String id = endpoint.getEndpointId().toString();
        // Only expose endpoints starting with "custom" or "health"
        return id.startsWith("custom") || id.equals("health");
    };
}

Accessing PathMappedEndpoints

@Component
public class EndpointPathService {

    private final PathMappedEndpoints pathMappedEndpoints;

    public EndpointPathService(PathMappedEndpoints pathMappedEndpoints) {
        this.pathMappedEndpoints = pathMappedEndpoints;
    }

    public String getHealthPath() {
        return pathMappedEndpoints.getPath(EndpointId.of("health"));
        // Returns: "/actuator/health" or custom mapping
    }

    public Collection<String> getAllPaths() {
        return pathMappedEndpoints.getAllPaths();
    }
}

Integration with Spring MVC/WebFlux

Spring MVC

Endpoints exposed via WebMvcEndpointHandlerMapping

Configuration:

@Configuration
public class MvcEndpointConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(
            WebEndpointsSupplier webEndpointsSupplier,
            ServletEndpointsSupplier servletEndpointsSupplier,
            ControllerEndpointsSupplier controllerEndpointsSupplier,
            EndpointMediaTypes endpointMediaTypes,
            CorsEndpointProperties corsProperties,
            WebEndpointProperties webEndpointProperties) {
        // Spring Boot auto-configures this
    }
}

Spring WebFlux

Endpoints exposed via WebFluxEndpointHandlerMapping

Security Integration

@Configuration
public class ActuatorSecurityConfiguration {

    @Bean
    public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
                .anyRequest().hasRole("ACTUATOR"))
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

Common Issues

Issue: Endpoints Return 404

Causes:

  1. Not exposed: Check management.endpoints.web.exposure.include
  2. Wrong path: Verify base path and mappings
  3. Wrong port: Check if using separate management port

Solution:

# Debug
management.endpoints.web.exposure.include=*
logging.level.org.springframework.boot.actuate.endpoint.web=DEBUG

Issue: CORS Errors

Cause: CORS not configured for actuator endpoints

Solution:

management.endpoints.web.cors.allowed-origins=https://frontend.example.com
management.endpoints.web.cors.allowed-methods=GET,POST

Issue: Wrong Base Path

Symptom: Endpoints at unexpected URLs

Check:

# These are cumulative
server.servlet.context-path=/app
management.server.base-path=/mgmt
management.endpoints.web.base-path=/actuator

# Result: /app/mgmt/actuator/<endpoint>

Performance Considerations

  • Discovery Page: Lightweight, no performance impact
  • Path Mapping: Resolved at startup, no runtime overhead
  • CORS: Standard Spring CORS filter overhead
  • Endpoint Invocation: Depends on endpoint implementation

Type System Reference

Web Endpoint Discovery

/**
 * Discovers web endpoints annotated with @Endpoint, @WebEndpoint, or @EndpointWebExtension
 */
public class WebEndpointDiscoverer {

    /**
     * Gets all discovered web endpoints
     * @return Collection of exposable web endpoints
     */
    public Collection<ExposableWebEndpoint> getEndpoints();
}

/**
 * Web endpoint that can be exposed via HTTP
 */
public interface ExposableWebEndpoint extends ExposableEndpoint<WebOperation>, PathMappedEndpoint {

    /**
     * Gets endpoint ID
     * @return The endpoint identifier
     */
    @Override
    EndpointId getEndpointId();

    /**
     * Gets all operations for this endpoint
     * @return Collection of web operations
     */
    @Override
    Collection<WebOperation> getOperations();

    /**
     * Whether endpoint is enabled by default
     * @return true if enabled by default
     */
    boolean isEnabledByDefault();

    /**
     * Gets root path for this endpoint
     * @return Root path relative to base path
     */
    @Override
    String getRootPath();
}

/**
 * Web endpoint operation
 */
public interface WebOperation extends Operation {

    /**
     * Gets HTTP request predicate (path, method, params, etc.)
     * @return The request predicate
     */
    WebOperationRequestPredicate getRequestPredicate();

    /**
     * Gets operation ID
     * @return The operation identifier
     */
    String getId();

    /**
     * Gets operation type (READ, WRITE, DELETE)
     * @return The operation type
     */
    OperationType getType();

    /**
     * Invokes the operation
     * @param context The invocation context
     * @return The operation result
     */
    Object invoke(InvocationContext context);
}

/**
 * Endpoint with path mapping
 * Note: PathMappedEndpoint implementations also implement ExposableEndpoint which provides getEndpointId()
 */
public interface PathMappedEndpoint {
    /**
     * Gets root path (relative to base path)
     * @return Root path (e.g., "health", "healthcheck")
     */
    String getRootPath();

    /**
     * Gets additional paths for the given web server namespace
     * @param webServerNamespace Web server namespace
     * @return List of additional paths
     * @since 3.4.0
     */
    default List<String> getAdditionalPaths(WebServerNamespace webServerNamespace) {
        return Collections.emptyList();
    }
}

Path Mapping

/**
 * Maps endpoint IDs to URL paths
 */
public interface PathMapper {
    /**
     * Gets the root path for an endpoint
     * @param endpointId Endpoint ID
     * @return Root path (e.g., "health" or "healthcheck")
     */
    String getRootPath(EndpointId endpointId);
}

/**
 * Path mapper based on WebEndpointProperties configuration
 */
class MappingWebEndpointPathMapper implements PathMapper {

    /**
     * Creates path mapper with custom path mappings
     * @param pathMapping Map of endpoint IDs to custom paths
     */
    public MappingWebEndpointPathMapper(Map<String, String> pathMapping);

    /**
     * Gets root path for endpoint, applying custom mapping if configured
     * @param endpointId The endpoint ID
     * @return The root path
     */
    @Override
    public String getRootPath(EndpointId endpointId);
}

CORS Configuration

/**
 * CORS configuration for management endpoints
 * Converts properties to Spring's CorsConfiguration
 */
@ConfigurationProperties("management.endpoints.web.cors")
public class CorsEndpointProperties {

    private List<String> allowedOrigins = new ArrayList<>();
    private List<String> allowedOriginPatterns = new ArrayList<>();
    private List<String> allowedMethods = new ArrayList<>();
    private List<String> allowedHeaders = new ArrayList<>();
    private List<String> exposedHeaders = new ArrayList<>();
    private Boolean allowCredentials;
    private Duration maxAge = Duration.ofSeconds(1800);

    /**
     * Converts these properties to Spring's CorsConfiguration
     * @return CorsConfiguration or null if no origins/origin patterns configured
     */
    public @Nullable CorsConfiguration toCorsConfiguration();

    // Standard getters and setters
    public List<String> getAllowedOrigins();
    public void setAllowedOrigins(List<String> allowedOrigins);

    public List<String> getAllowedOriginPatterns();
    public void setAllowedOriginPatterns(List<String> allowedOriginPatterns);

    public List<String> getAllowedMethods();
    public void setAllowedMethods(List<String> allowedMethods);

    public List<String> getAllowedHeaders();
    public void setAllowedHeaders(List<String> allowedHeaders);

    public List<String> getExposedHeaders();
    public void setExposedHeaders(List<String> exposedHeaders);

    public Boolean getAllowCredentials();
    public void setAllowCredentials(Boolean allowCredentials);

    public Duration getMaxAge();
    public void setMaxAge(Duration maxAge);
}

Endpoint Suppliers

/**
 * Supplies a collection of endpoints
 * @param <E> Type of exposable endpoint
 */
@FunctionalInterface
public interface EndpointsSupplier<E extends ExposableEndpoint<?>> {
    /**
     * Gets all endpoints
     * @return Collection of endpoints
     */
    Collection<E> getEndpoints();
}

/**
 * Supplies web endpoints
 */
public interface WebEndpointsSupplier extends EndpointsSupplier<ExposableWebEndpoint> {
    /**
     * Gets all web endpoints
     * @return Collection of web endpoints
     */
    @Override
    Collection<ExposableWebEndpoint> getEndpoints();
}

Media Types

/**
 * Media types supported by endpoints
 */
public class EndpointMediaTypes {
    private final List<String> produced;
    private final List<String> consumed;

    /**
     * Creates endpoint media types
     * @param produced Media types produced by endpoints
     * @param consumed Media types consumed by endpoints
     */
    public EndpointMediaTypes(List<String> produced, List<String> consumed);

    /**
     * Gets media types produced by endpoints
     * Default: ["application/vnd.spring-boot.actuator.v3+json", "application/json"]
     * @return Produced media types
     */
    public List<String> getProduced();

    /**
     * Gets media types consumed by endpoints
     * Default: ["application/vnd.spring-boot.actuator.v3+json", "application/json"]
     * @return Consumed media types
     */
    public List<String> getConsumed();
}

Related Documentation

Within This Tile

  • index.md - Complete overview with decision matrices and patterns
    • See "Decision Matrices" → "When to Use Separate Management Port"
    • See "Architecture Integration Flow" → step 4 for web exposure in the overall flow
    • See "Common Configuration Scenarios" for complete examples
  • core-infrastructure.md - Foundation infrastructure
    • WebEndpointAutoConfiguration depends on EndpointAutoConfiguration
    • Uses ParameterValueMapper and EndpointAccessResolver from core
  • management-endpoints.md - Endpoints being exposed
    • Lists all available endpoints that can be exposed via web
    • See endpoint-specific HTTP methods and operations
  • endpoint-filtering.md - Controlling exposure
    • IncludeExcludeEndpointFilter works with web exposure properties
    • Filter evaluation happens before web exposure
  • management-server.md - Separate management port
    • Alternative to exposing on main application port
    • Independent SSL, base path, and network binding
  • endpoint-properties.md - Endpoint-specific config
    • CORS properties detailed here
    • Show-values and security properties
  • jmx-endpoints.md - Alternative exposure technology
    • Same endpoints, different exposure mechanism (JMX vs HTTP)
  • conditional-annotations.md - Conditional configuration
    • @ConditionalOnAvailableEndpoint with exposure=WEB checks web exposure

Quick Navigation

From Web Endpoints, you can:

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-actuator-autoconfigure

docs

conditional-annotations.md

core-infrastructure.md

endpoint-filtering.md

endpoint-properties.md

index.md

jmx-endpoints.md

management-endpoints.md

management-server.md

web-endpoints.md

tile.json