Spring Boot Actuator AutoConfigure module providing production-ready features to Spring Boot applications through auto-configuration
—
Configuration for HTTP exposure of Spring Boot Actuator endpoints, including path mapping, filtering, CORS, and discovery.
# 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,POSThttp://<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)@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
);
}
}@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
}
}| Endpoint ID | Default Path | Configurable Via |
|---|---|---|
| health | /actuator/health | management.endpoints.web.path-mapping.health |
| info | /actuator/info | management.endpoints.web.path-mapping.info |
| metrics | /actuator/metrics | management.endpoints.web.path-mapping.metrics |
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=statsResult:
/management/status (was /actuator/health)/management/about (was /actuator/info)/management/stats (was /actuator/metrics)@Bean
public PathMapper customPathMapper() {
return endpointId -> {
String id = endpointId.toString();
return switch (id) {
case "health" -> "healthcheck";
case "info" -> "information";
default -> id;
};
};
}# 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=3600Development (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=trueProduction (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=3600URL: <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# 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/**
* 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
}Default Produced: application/vnd.spring-boot.actuator.v3+json, application/json
Default Consumed: application/vnd.spring-boot.actuator.v3+json, application/json
@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");
};
}@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();
}
}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
}
}Endpoints exposed via WebFluxEndpointHandlerMapping
@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();
}
}Causes:
management.endpoints.web.exposure.includeSolution:
# Debug
management.endpoints.web.exposure.include=*
logging.level.org.springframework.boot.actuate.endpoint.web=DEBUGCause: CORS not configured for actuator endpoints
Solution:
management.endpoints.web.cors.allowed-origins=https://frontend.example.com
management.endpoints.web.cors.allowed-methods=GET,POSTSymptom: 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>/**
* 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();
}
}/**
* 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 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);
}/**
* 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 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();
}From Web Endpoints, you can:
Install with Tessl CLI
npx tessl i tessl/maven-org-springframework-boot--spring-boot-actuator-autoconfigure