Spring Boot Actuator AutoConfigure module providing production-ready features to Spring Boot applications through auto-configuration
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Spring Boot Actuator AutoConfigure provides automatic configuration for Spring Boot Actuator, enabling production-ready monitoring and management features. It auto-configures actuator endpoints based on classpath dependencies and application properties, following Spring Boot's convention-over-configuration philosophy. This module handles endpoint discovery, filtering, exposure (via HTTP and JMX), and management server configuration.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency># Expose all web endpoints
management.endpoints.web.exposure.include=*
# Expose specific endpoints
management.endpoints.web.exposure.include=health,info,metrics
# Change base path
management.endpoints.web.base-path=/actuator
# Separate management port
management.server.port=8081
# Endpoint access control
management.endpoint.health.show-details=always
management.endpoint.env.show-values=NEVER// Endpoint annotations
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
// Conditional annotations
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
// Core infrastructure
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.EndpointId;
// Properties
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;| Scenario | Same Port | Separate Port | Reason |
|---|---|---|---|
| Simple application | ✓ | Less complexity | |
| Production with network isolation needed | ✓ | Can restrict management access | |
| Docker/Kubernetes | ✓ | Liveness/readiness on main port | |
| Internal monitoring tools | ✓ | Separate security policies | |
| High-security requirements | ✓ | Firewall rules isolation |
| Environment | Web Exposure | JMX Exposure | Rationale |
|---|---|---|---|
| Development | * | * | Full visibility for debugging |
| Staging | health,info,metrics,loggers | * | Limited web, full internal |
| Production | health,info,metrics,prometheus | health,metrics | Minimal exposure |
| Environment | configprops | env | Rationale |
|---|---|---|---|
| Development | ALWAYS | ALWAYS | Full visibility |
| Staging | WHEN_AUTHORIZED | WHEN_AUTHORIZED | Role-based access |
| Production | NEVER | NEVER | Maximum security |
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> getData() {
return Map.of("status", "ok", "timestamp", System.currentTimeMillis());
}
}Property required: management.endpoints.web.exposure.include=custom
// Endpoint class
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> getData() {
return Map.of("status", "ok");
}
}
// Auto-configuration
@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = CustomEndpoint.class)
public class CustomEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public CustomEndpoint customEndpoint() {
return new CustomEndpoint();
}
}@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("custom", Map.of("key", "value"));
}
}Property required: management.info.custom.enabled=true
@Endpoint(id = "cache")
public class CacheEndpoint {
@ReadOperation
public Map<String, Object> getCache(@Selector String cacheName) {
// GET /actuator/cache/{cacheName}
return cacheManager.getCache(cacheName).asMap();
}
@DeleteOperation
public void evictCache(@Selector String cacheName) {
// DELETE /actuator/cache/{cacheName}
cacheManager.getCache(cacheName).clear();
}
}// Register in META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports
@ManagementContextConfiguration(ManagementContextType.CHILD)
public class CustomManagementConfiguration {
@Bean
public CustomManagementBean customBean() {
return new CustomManagementBean();
}
}┌─────────────────────────────────────────────────────────┐
│ Endpoint Auto-Configuration Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Endpoint │ │ Endpoint │ │ Endpoint │ │
│ │ Discovery │→ │ Filtering │→ │ Exposure │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Exposure Technology Layer │
│ ┌──────────────────┐ ┌───────────────────┐ │
│ │ Web Endpoints │ │ JMX Endpoints │ │
│ │ (HTTP/JSON) │ │ (MBeans) │ │
│ └──────────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Server Infrastructure Layer │
│ ┌──────────────────┐ ┌───────────────────┐ │
│ │ Same Server │ OR │ Separate Server │ │
│ │ (server.port) │ │ (mgmt.port) │ │
│ └──────────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────┘| Subsystem | Documentation | Key Classes | Primary Use |
|---|---|---|---|
| Core Infrastructure | core-infrastructure.md | EndpointAutoConfiguration, PropertiesEndpointAccessResolver | Endpoint parameter mapping, caching, access control |
| Management Endpoints | management-endpoints.md | BeansEndpoint, HealthEndpoint, InfoEndpoint, etc. | Individual endpoint implementations |
| Web Exposure | web-endpoints.md | WebEndpointAutoConfiguration, WebEndpointProperties | HTTP endpoint exposure, CORS, path mapping |
| JMX Exposure | jmx-endpoints.md | JmxEndpointAutoConfiguration, JmxEndpointProperties | JMX MBean endpoint exposure |
| Endpoint Properties | endpoint-properties.md | ConfigurationPropertiesReportEndpointProperties, EnvironmentEndpointProperties | Endpoint-specific configuration |
| Endpoint Filtering | endpoint-filtering.md | IncludeExcludeEndpointFilter, EndpointExposure | Include/exclude pattern filtering |
| Management Server | management-server.md | ManagementServerProperties, ManagementPortType | Separate management port configuration |
| Conditional Annotations | conditional-annotations.md | @ConditionalOnAvailableEndpoint, @ConditionalOnManagementPort | Conditional component registration |
| Endpoint ID | Path | HTTP Methods | Default Exposed | Purpose | Auto-Config Class |
|---|---|---|---|---|---|
health | /actuator/health | GET | Yes (web, jmx) | Application health status | (In spring-boot-health module) |
info | /actuator/info | GET | Yes (web) | Application information | InfoEndpointAutoConfiguration |
metrics | /actuator/metrics | GET | No | Application metrics | (In spring-boot-actuator-metrics module) |
beans | /actuator/beans | GET | No | All Spring beans | BeansEndpointAutoConfiguration |
conditions | /actuator/conditions | GET | No | Auto-configuration report | ConditionsReportEndpointAutoConfiguration |
configprops | /actuator/configprops | GET | No | Configuration properties | ConfigurationPropertiesReportEndpointAutoConfiguration |
env | /actuator/env | GET | No | Environment properties | EnvironmentEndpointAutoConfiguration |
loggers | /actuator/loggers | GET, POST | No | Logger levels (mutable) | LoggersEndpointAutoConfiguration |
heapdump | /actuator/heapdump | GET | No | Download heap dump | HeapDumpWebEndpointAutoConfiguration |
threaddump | /actuator/threaddump | GET | No | Thread dump | ThreadDumpEndpointAutoConfiguration |
shutdown | /actuator/shutdown | POST | No | Graceful shutdown | ShutdownEndpointAutoConfiguration |
mappings | /actuator/mappings | GET | No | Request mappings | MappingsEndpointAutoConfiguration |
scheduledtasks | /actuator/scheduledtasks | GET | No | Scheduled tasks | ScheduledTasksEndpointAutoConfiguration |
httpexchanges | /actuator/httpexchanges | GET | No | HTTP request/response log | HttpExchangesEndpointAutoConfiguration |
auditevents | /actuator/auditevents | GET | No | Security audit events | AuditEventsEndpointAutoConfiguration |
sbom | /actuator/sbom | GET | No | Software Bill of Materials | SbomEndpointAutoConfiguration |
startup | /actuator/startup | GET | No | Application startup info | StartupEndpointAutoConfiguration |
logfile | /actuator/logfile | GET | No | Download log file | LogFileWebEndpointAutoConfiguration |
# Default: health (both web and jmx)
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=shutdown
management.endpoints.jmx.exposure.include=*
management.endpoints.jmx.exposure.exclude=
# Base paths
management.endpoints.web.base-path=/actuator
management.server.base-path=# Access levels: UNRESTRICTED, READ_ONLY, NONE
management.endpoints.access.default=READ_ONLY
management.endpoints.access.max-permitted=UNRESTRICTED
management.endpoint.<id>.access=UNRESTRICTED# Port configuration
management.server.port=8081 # Separate port
management.server.port=-1 # Disable management
# (not set = same as server.port)
management.server.address=127.0.0.1 # Bind address
management.server.base-path=/admin # Additional base path# Health
management.endpoint.health.show-details=always|never|when-authorized
# Environment & ConfigProps
management.endpoint.env.show-values=NEVER|ALWAYS|WHEN_AUTHORIZED
management.endpoint.env.roles=ADMIN
management.endpoint.configprops.show-values=NEVER|ALWAYS|WHEN_AUTHORIZED
management.endpoint.configprops.roles=ADMIN
# Info Contributors
management.info.git.enabled=true
management.info.git.mode=SIMPLE|FULL
management.info.env.enabled=true
management.info.java.enabled=true
management.info.defaults.enabled=true
# HTTP Exchanges
management.httpexchanges.recording.include=TIME_TAKEN,REQUEST_HEADERS,RESPONSE_HEADERS
# Caching
management.endpoint.<id>.cache.time-to-live=10smanagement.endpoints.web.cors.allowed-origins=https://example.com
management.endpoints.web.cors.allowed-methods=GET,POST
management.endpoints.web.cors.allowed-headers=*
management.endpoints.web.cors.allow-credentials=true
management.endpoints.web.cors.max-age=3600Core infrastructure for endpoint discovery, filtering, parameter mapping, caching, and access control.
@AutoConfiguration
public final class EndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
ParameterValueMapper endpointOperationParameterMapper(
@EndpointConverter ObjectProvider<Converter<?, ?>> converters,
@EndpointConverter ObjectProvider<GenericConverter> genericConverters
);
@Bean
@ConditionalOnMissingBean
CachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor(Environment environment);
@Bean
@ConditionalOnMissingBean(EndpointAccessResolver.class)
PropertiesEndpointAccessResolver propertiesEndpointAccessResolver(Environment environment);
}
public class PropertiesEndpointAccessResolver implements EndpointAccessResolver {
public Access accessFor(EndpointId endpointId, Access defaultAccess);
}Configures JSON serialization for endpoint responses using Jackson.
/**
* Auto-configuration for endpoint JSON serialization (Jackson 3)
*/
@AutoConfiguration
@ConditionalOnClass(JsonMapper.class)
public final class JacksonEndpointAutoConfiguration {
/**
* Provides isolated JSON mapper for endpoint serialization
* Uses separate ObjectMapper instance to avoid conflicts with application JSON configuration
*/
@Bean
@ConditionalOnBooleanProperty(name = "management.endpoints.jackson.isolated-json-mapper", matchIfMissing = true)
EndpointJsonMapper endpointJsonMapper();
}
/**
* Auto-configuration for endpoint JSON serialization (Jackson 2 - DEPRECATED)
* @deprecated since 4.0.0, scheduled for removal in 4.2.0
* Use JacksonEndpointAutoConfiguration instead (Jackson 3)
*/
@Deprecated(since = "4.0.0", forRemoval = true)
@SuppressWarnings("removal")
@AutoConfiguration
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
public final class Jackson2EndpointAutoConfiguration {
/**
* Provides Jackson 2 based JSON mapper for endpoints
* @deprecated Use JacksonEndpointAutoConfiguration instead
*/
@Bean
@Deprecated(since = "4.0.0", forRemoval = true)
EndpointJackson2ObjectMapper jackson2EndpointJsonMapper();
}Properties:
# Jackson 3 - Enable/disable isolated JSON mapper (default: true)
management.endpoints.jackson.isolated-json-mapper=true
# Jackson 2 (deprecated) - Enable/disable isolated object mapper (default: true)
management.endpoints.jackson2.isolated-object-mapper=trueKey Features:
Migration Note: Applications using Jackson 2 should migrate to Jackson 3. Jackson2EndpointAutoConfiguration is deprecated since 4.0.0 and will be removed in 4.2.0.
Configures HTTP exposure of actuator endpoints, including path mapping, filtering, and CORS.
@AutoConfiguration
@ConditionalOnWebApplication
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
PathMappedEndpoints pathMappedEndpoints(
Collection<EndpointsSupplier<?>> endpointSuppliers
);
}
@ConfigurationProperties("management.endpoints.web")
public class WebEndpointProperties {
private String basePath = "/actuator";
private Map<String, String> pathMapping = new LinkedHashMap<>();
private Exposure exposure = new Exposure();
private Discovery discovery = new Discovery();
public static class Exposure {
private Set<String> include = new LinkedHashSet<>();
private Set<String> exclude = new LinkedHashSet<>();
}
}
@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 to Spring CorsConfiguration
* @return CorsConfiguration or null if no origins/origin patterns configured
*/
public @Nullable CorsConfiguration toCorsConfiguration();
}Configures JMX MBean exposure of actuator endpoints.
@AutoConfiguration
@ConditionalOnBooleanProperty("spring.jmx.enabled")
public final class JmxEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean(JmxEndpointsSupplier.class)
JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer(
ParameterValueMapper parameterValueMapper,
ObjectProvider<OperationInvokerAdvisor> invokerAdvisors,
ObjectProvider<EndpointFilter<ExposableJmxEndpoint>> endpointFilters,
ObjectProvider<OperationFilter<JmxOperation>> operationFilters
);
@Bean
@ConditionalOnMissingBean(value = EndpointObjectNameFactory.class, search = SearchStrategy.CURRENT)
DefaultEndpointObjectNameFactory endpointObjectNameFactory(MBeanServer mBeanServer);
/**
* JmxEndpointExporter is configured in nested configuration classes
* See: JmxEndpointConfiguration and JmxEndpointDiscoveryConfiguration
*/
@Bean
JmxEndpointExporter jmxEndpointExporter(
JmxEndpointDiscoverer jmxEndpointDiscoverer,
EndpointObjectNameFactory endpointObjectNameFactory
);
}
@ConfigurationProperties("management.endpoints.jmx")
public class JmxEndpointProperties {
private String domain;
private Properties staticNames = new Properties();
private Exposure exposure = new Exposure();
public static class Exposure {
private Set<String> include = new LinkedHashSet<>();
private Set<String> exclude = new LinkedHashSet<>();
}
}Configures a separate management server on a different port with independent SSL configuration.
/**
* Auto-configuration for management context initialization
* Creates child management context when using separate management port
* Contains nested configurations for SAME and DIFFERENT management port types
*/
@AutoConfiguration
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public final class ManagementContextAutoConfiguration {
/**
* Configuration for when management endpoints run on same port as application
* Validates that management-specific SSL and address are not configured
* Adds 'local.management.port' property alias
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnManagementPort(ManagementPortType.SAME)
static class SameManagementContextConfiguration implements SmartInitializingSingleton {
/**
* Constructor injecting environment for validation
* @param environment Spring environment
*/
SameManagementContextConfiguration(Environment environment);
/**
* Called after all singletons are instantiated
* Performs validation and property alias setup
*/
@Override
void afterSingletonsInstantiated();
/**
* Inner configuration that enables ManagementContextConfiguration imports
* for SAME context type
*/
@Configuration(proxyBeanMethods = false)
@EnableManagementContext(ManagementContextType.SAME)
static class EnableSameManagementContextConfiguration {
}
}
/**
* Configuration for when management endpoints run on different port
* Enables ManagementServerProperties and creates child context initializer
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
@EnableConfigurationProperties(ManagementServerProperties.class)
static class DifferentManagementContextConfiguration {
/**
* Creates child management context initializer for separate management port
* ManagementContextFactory is injected as parameter (not created by this config)
* @param managementContextFactory Factory for creating management context
* @param parentContext The parent application context
* @return Child context initializer
*/
@Bean
static ChildManagementContextInitializer childManagementContextInitializer(
ManagementContextFactory managementContextFactory,
AbstractApplicationContext parentContext
);
}
}
@ConfigurationProperties("management.server")
public class ManagementServerProperties {
private Integer port;
private InetAddress address;
private String basePath = "";
/**
* SSL configuration for management server
* Type: org.springframework.boot.web.server.Ssl (from Spring Boot core)
* Only applies when using separate management port (ManagementPortType.DIFFERENT)
* Uses standard Spring Boot SSL configuration properties
*/
private Ssl ssl;
}
public enum ManagementPortType {
DISABLED, // management.server.port=-1
SAME, // port not specified or same as server.port
DIFFERENT; // different port specified
public static ManagementPortType get(Environment environment);
}Management Server Configuration
Custom Spring conditional annotations for endpoint availability and configuration.
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Conditional(OnAvailableEndpointCondition.class)
public @interface ConditionalOnAvailableEndpoint {
Class<?> endpoint() default Void.class;
Class<?> value() default Void.class;
EndpointExposure[] exposure() default {};
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Conditional(OnEnabledInfoContributorCondition.class)
public @interface ConditionalOnEnabledInfoContributor {
String value();
InfoContributorFallback fallback() default InfoContributorFallback.USE_DEFAULTS_PROPERTY;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Conditional(OnManagementPortCondition.class)
public @interface ConditionalOnManagementPort {
ManagementPortType value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Configuration(proxyBeanMethods = false)
public @interface ManagementContextConfiguration {
ManagementContextType value() default ManagementContextType.ANY;
boolean proxyBeanMethods() default true;
}Filters and discovers endpoints based on include/exclude patterns and access control.
public class IncludeExcludeEndpointFilter<E extends ExposableEndpoint<?>> implements EndpointFilter<E> {
public IncludeExcludeEndpointFilter(Class<E> endpointType, Environment environment, String prefix, String... defaultIncludes);
public IncludeExcludeEndpointFilter(Class<E> endpointType, Collection<String> include, Collection<String> exclude, String... defaultIncludes);
public boolean match(E endpoint);
public boolean match(EndpointId id);
}
public enum EndpointExposure {
JMX,
WEB;
public String[] getDefaultIncludes();
}
public interface EndpointExposureOutcomeContributor {
@Nullable
ConditionOutcome getExposureOutcome(
EndpointId endpointId,
Set<EndpointExposure> exposures,
ConditionMessage.Builder message
);
}Individual endpoint auto-configurations for monitoring, diagnostics, and application information.
Available Endpoints:
/auditevents) - Security audit event recording/beans) - Application context bean information/conditions) - Auto-configuration report/configprops) - @ConfigurationProperties beans/env) - Environment properties and property sources/heapdump) - Heap dump download/httpexchanges) - HTTP request/response recording/info) - Application information from contributors/logfile) - Log file download/loggers) - Logger levels (view and modify)/mappings) - Request mapping paths/sbom) - Software Bill of Materials/scheduledtasks) - Scheduled task information/shutdown) - Graceful application shutdown/startup) - Application startup information/threaddump) - Thread dump information// Example: Beans Endpoint
@AutoConfiguration
@ConditionalOnAvailableEndpoint(endpoint = BeansEndpoint.class)
public final class BeansEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
BeansEndpoint beansEndpoint(ConfigurableApplicationContext applicationContext);
}
// Example: Conditions Report Endpoint
@Endpoint(id = "conditions")
public class ConditionsReportEndpoint {
@ReadOperation
public ConditionsDescriptor conditions();
public static final class ConditionsDescriptor implements OperationResponseBody {
private final Map<String, ContextConditionsDescriptor> contexts;
/**
* Creates a conditions descriptor
* Private constructor - used internally by the endpoint
* @param contexts Map of context ID to context conditions
*/
private ConditionsDescriptor(Map<@Nullable String, ContextConditionsDescriptor> contexts);
public Map<String, ContextConditionsDescriptor> getContexts();
}
@JsonInclude(Include.NON_EMPTY)
public static final class ContextConditionsDescriptor {
private final Map<String, List<MessageAndConditionDescriptor>> positiveMatches;
private final Map<String, MessageAndConditionsDescriptor> negativeMatches;
private final List<String> exclusions;
private final Set<String> unconditionalClasses;
private final @Nullable String parentId;
/**
* Creates a context conditions descriptor from application context
* @param context The application context to analyze
*/
public ContextConditionsDescriptor(ConfigurableApplicationContext context);
public Map<String, List<MessageAndConditionDescriptor>> getPositiveMatches();
public Map<String, MessageAndConditionsDescriptor> getNegativeMatches();
public List<String> getExclusions();
public Set<String> getUnconditionalClasses();
public @Nullable String getParentId();
}
@JsonPropertyOrder({ "notMatched", "matched" })
public static class MessageAndConditionsDescriptor {
private final List<MessageAndConditionDescriptor> notMatched;
private final List<MessageAndConditionDescriptor> matched;
/**
* Creates a descriptor from condition and outcomes
* @param conditionAndOutcomes The conditions and their evaluation outcomes
*/
public MessageAndConditionsDescriptor(ConditionAndOutcomes conditionAndOutcomes);
public List<MessageAndConditionDescriptor> getNotMatched();
public List<MessageAndConditionDescriptor> getMatched();
}
@JsonPropertyOrder({ "condition", "message" })
public static class MessageAndConditionDescriptor {
private final String condition;
private final String message;
/**
* Creates a descriptor from single condition and outcome
* @param conditionAndOutcome The condition and its evaluation outcome
*/
public MessageAndConditionDescriptor(ConditionAndOutcome conditionAndOutcome);
public String getCondition();
public String getMessage();
}
}
// Example: Info Endpoint with Contributors
@AutoConfiguration(after = InfoContributorAutoConfiguration.class)
@ConditionalOnAvailableEndpoint(endpoint = InfoEndpoint.class)
public final class InfoEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
InfoEndpoint infoEndpoint(ObjectProvider<InfoContributor> infoContributors);
}
@AutoConfiguration(after = ProjectInfoAutoConfiguration.class)
@EnableConfigurationProperties(InfoContributorProperties.class)
public final class InfoContributorAutoConfiguration {
/**
* The default order for the core {@link InfoContributor} beans.
* Set to HIGHEST_PRECEDENCE + 10 to run before most other contributors.
*/
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
@Bean
@Order(DEFAULT_ORDER)
@ConditionalOnEnabledInfoContributor(value = "env", fallback = InfoContributorFallback.DISABLE)
public EnvironmentInfoContributor envInfoContributor(ConfigurableEnvironment environment);
@Bean
@ConditionalOnEnabledInfoContributor("git")
@ConditionalOnSingleCandidate(GitProperties.class)
@ConditionalOnMissingBean
@Order(DEFAULT_ORDER)
public GitInfoContributor gitInfoContributor(GitProperties gitProperties, InfoContributorProperties infoContributorProperties);
@Bean
@ConditionalOnEnabledInfoContributor("build")
@ConditionalOnSingleCandidate(BuildProperties.class)
@Order(DEFAULT_ORDER)
public InfoContributor buildInfoContributor(BuildProperties properties);
@Bean
@Order(DEFAULT_ORDER)
@ConditionalOnEnabledInfoContributor(value = "java", fallback = InfoContributorFallback.DISABLE)
public JavaInfoContributor javaInfoContributor();
@Bean
@Order(DEFAULT_ORDER)
@ConditionalOnEnabledInfoContributor(value = "os", fallback = InfoContributorFallback.DISABLE)
public OsInfoContributor osInfoContributor();
@Bean
@Order(DEFAULT_ORDER)
@ConditionalOnEnabledInfoContributor(value = "process", fallback = InfoContributorFallback.DISABLE)
public ProcessInfoContributor processInfoContributor();
@Bean
@Order(DEFAULT_ORDER)
@ConditionalOnEnabledInfoContributor(value = "ssl", fallback = InfoContributorFallback.DISABLE)
public SslInfoContributor sslInfoContributor(SslInfo sslInfo);
@Bean
@ConditionalOnMissingBean
public SslInfo sslInfo(SslBundles sslBundles);
}Typed configuration classes for endpoint-specific settings.
import org.springframework.boot.actuate.endpoint.Show;
@ConfigurationProperties("management.endpoint.configprops")
public class ConfigurationPropertiesReportEndpointProperties {
private Show showValues = Show.NEVER;
private Set<String> roles = new LinkedHashSet<>();
}
@ConfigurationProperties("management.endpoint.env")
public class EnvironmentEndpointProperties {
private Show showValues = Show.NEVER;
private Set<String> roles = new LinkedHashSet<>();
}
// Note: Show enum is defined in org.springframework.boot.actuate.endpoint.Show
// (spring-boot-actuator module). See Type System Reference section below.
@ConfigurationProperties("management.endpoint.logfile")
public class LogFileWebEndpointProperties {
private File externalFile;
}
@ConfigurationProperties("management.info")
public class InfoContributorProperties {
private Git git = new Git();
/**
* Gets the Git info contributor properties
* @return Git properties
*/
public Git getGit();
/**
* Git info contributor properties
*/
public static class Git {
/**
* Mode to use to expose git information
* Default: SIMPLE
*
* Note: GitInfoContributor.Mode is from org.springframework.boot.actuate.info
* (spring-boot-actuator module, not autoconfigure)
*/
private GitInfoContributor.Mode mode = GitInfoContributor.Mode.SIMPLE;
/**
* Gets the git info mode
* @return The git info mode
*/
public GitInfoContributor.Mode getMode();
/**
* Sets the git info mode
* @param mode The git info mode
*/
public void setMode(GitInfoContributor.Mode mode);
}
}
@ConfigurationProperties("management.httpexchanges")
public class HttpExchangesProperties {
private Recording recording = new Recording();
public static class Recording {
/**
* Items to be included in the exchange recording
* Defaults to TIME_TAKEN, REQUEST_HEADERS, and RESPONSE_HEADERS
* (excluding Authorization and Cookie headers)
*
* Note: Include enum is from org.springframework.boot.actuate.web.exchanges.Include
* (spring-boot-actuator module, not autoconfigure)
*/
private Set<Include> include = new HashSet<>(Include.defaultIncludes());
/**
* Include enum type - from spring-boot-actuator module
* Package: org.springframework.boot.actuate.web.exchanges
*/
public enum Include {
REQUEST_HEADERS,
RESPONSE_HEADERS,
COOKIE_HEADERS,
AUTHORIZATION_HEADER,
TIME_TAKEN,
PRINCIPAL,
REMOTE_ADDRESS,
SESSION_ID;
/**
* Returns the default includes: TIME_TAKEN, REQUEST_HEADERS, RESPONSE_HEADERS
*/
public static Set<Include> defaultIncludes();
}
}
}Endpoint Configuration Properties
management.endpoints.web.exposure.include=*
management.endpoint.env.show-values=ALWAYS
management.endpoint.configprops.show-values=ALWAYS
management.httpexchanges.recording.include=REQUEST_HEADERS,RESPONSE_HEADERS,TIME_TAKENmanagement.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoints.web.exposure.exclude=shutdown,heapdump,threaddump
management.endpoint.env.show-values=NEVER
management.endpoint.configprops.show-values=NEVER
management.server.port=8081
management.server.address=127.0.0.1# Health checks on main port
management.endpoint.health.probes.enabled=true
server.port=8080
# Full actuator on separate internal port
management.server.port=8081
management.server.address=0.0.0.0
management.endpoints.web.exposure.include=*server.port=8080
management.server.port=8443
management.server.ssl.enabled=true
management.server.ssl.key-store=classpath:mgmt-keystore.p12
management.server.ssl.key-store-password=changeit
management.endpoints.web.exposure.include=health,info,metricsPossible causes:
management.endpoints.web.exposure.includemanagement.endpoint.<id>.access or .enabledmanagement.endpoints.web.base-path and path mappingsSolution:
# Debug exposure
management.endpoints.web.exposure.include=*
logging.level.org.springframework.boot.actuate=DEBUGPossible causes:
show-values set to ALWAYS in productionSolution:
management.endpoint.env.show-values=NEVER
management.endpoint.configprops.show-values=NEVER
management.endpoints.web.exposure.include=health,info,metricsSymptom: Address already in use on management port
Solution:
# Change management port or use same port
management.server.port=8082
# OR
management.server.port=${server.port}Possible causes:
@Component or @Bean registration@ConditionalOnAvailableEndpoint condition not metSolution:
// Ensure @Component or @Bean
@Component
@Endpoint(id = "custom")
public class CustomEndpoint { }# Ensure exposed
management.endpoint.custom.access=UNRESTRICTED
management.endpoints.web.exposure.include=customPossible causes:
info.* properties setgit.properties or build-info.propertiesSolution:
# Enable contributors
management.info.git.enabled=true
management.info.env.enabled=true
management.info.java.enabled=true
# Add custom info
info.app.name=My Application
info.app.version=1.0.0| Feature | Min Version | Notes |
|---|---|---|
| Jackson 3 support | 4.0.0 | Jackson 2 deprecated, removed in 4.2.0 |
access property (vs enabled) | 3.4.0 | enabled deprecated |
@ManagementContextConfiguration | 2.0.0 | For child context configuration |
EndpointExposureOutcomeContributor | 3.4.0 | SPI for custom exposure logic |
@ReadOperation methods should be fast (<1s typical)| Endpoint | Limitation | Workaround |
|---|---|---|
heapdump | Only works with HotSpot JVM | Not available on other JVMs |
threaddump | May impact performance under load | Use sampling profiler instead |
logfile | Requires file-based logging | Configure logging.file.name |
shutdown | Irreversible operation | Requires explicit enablement |
httpexchanges | In-memory only, limited capacity | Use dedicated APM tool for production |
auditevents | Requires AuditEventRepository bean | Implement custom repository |
startup | Requires BufferingApplicationStartup | Configure at application start |
# DON'T
management.endpoints.web.exposure.include=*Why: Exposes sensitive information and dangerous operations.
Do instead:
# DO
management.endpoints.web.exposure.include=health,info,metrics,prometheus# DON'T
management.endpoint.env.show-values=ALWAYS
management.endpoint.configprops.show-values=ALWAYSWhy: Exposes secrets, passwords, API keys.
Do instead:
# DO
management.endpoint.env.show-values=WHEN_AUTHORIZED
management.endpoint.env.roles=ADMIN// DON'T
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) {
http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}Do instead:
// DO
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) {
http.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.anyRequest().hasRole("ACTUATOR"));
return http.build();
}// DON'T
@Endpoint(id = "slow")
public class SlowEndpoint {
@ReadOperation
public String getData() throws InterruptedException {
Thread.sleep(30000); // Blocks for 30 seconds
return "data";
}
}Do instead:
// DO
@Endpoint(id = "fast")
public class FastEndpoint {
@ReadOperation
public String getData() {
return cache.get("data"); // Quick cache lookup
}
}/**
* Endpoint access levels
* Controls what operations can be performed on an endpoint
* @since 3.4.0
*/
public enum Access {
/**
* UNRESTRICTED - Full access to all operations
* Allows READ, WRITE, and DELETE operations
* Use for: Public endpoints like health, info
*/
UNRESTRICTED,
/**
* READ_ONLY - Read operations only
* Allows READ operations, blocks WRITE and DELETE
* Use for: Endpoints that should be monitored but not modified (beans, env, metrics)
*/
READ_ONLY,
/**
* NONE - Endpoint is disabled
* Blocks all operations, endpoint will not be exposed
* Use for: Disabling specific endpoints (shutdown, threaddump in production)
*/
NONE
}
/**
* Operation types for endpoints
*/
public enum OperationType {
READ, // Query operation (safe, idempotent) - maps to HTTP GET
WRITE, // Mutating operation - maps to HTTP POST/PUT
DELETE // Deletion operation - maps to HTTP DELETE
}
/**
* Endpoint exposure technologies
*/
public enum EndpointExposure {
JMX, // JMX MBean exposure
WEB; // HTTP/JSON exposure
/**
* Gets default includes for this exposure type
* @return Array of endpoint IDs to include by default
*/
public String[] getDefaultIncludes();
}
/**
* Management port types for @ConditionalOnManagementPort
*/
public enum ManagementPortType {
/**
* Management endpoints disabled (management.server.port=-1)
*/
DISABLED,
/**
* Management endpoints on same port as application
* Used when management.server.port is not set or same as server.port
*/
SAME,
/**
* Management endpoints on separate port
* Used when management.server.port is set to a different port
*/
DIFFERENT;
/**
* Determines the management port type from environment
* @param environment Spring environment
* @return The management port type
*/
public static ManagementPortType get(Environment environment);
}
/**
* Management context types for @ManagementContextConfiguration
* @since 2.0.0
*/
public enum ManagementContextType {
/**
* Management endpoints in same context as application
* Used when management.server.port is not set or same as server.port
*/
SAME,
/**
* Management endpoints in separate child context
* Used when management.server.port is set to a different port
*/
CHILD,
/**
* Configuration applies to any context type (default)
* Used for configurations that should be available in both SAME and CHILD contexts
*/
ANY
}
/**
* Controls when to show unsanitized property values in endpoints
* Used by ConfigurationPropertiesReportEndpointProperties and EnvironmentEndpointProperties
* Located in: org.springframework.boot.actuate.endpoint.Show (spring-boot-actuator module)
* @since 2.0.0
*/
public enum Show {
/**
* Never show unsanitized values (always sanitize sensitive data)
*/
NEVER,
/**
* Always show unsanitized values (not recommended in production)
*/
ALWAYS,
/**
* Show unsanitized values only when user has required roles
*/
WHEN_AUTHORIZED
}
/**
* Info contributor fallback behavior
*/
public enum InfoContributorFallback {
USE_DEFAULTS_PROPERTY, // Use management.info.defaults.enabled as fallback
DISABLE // Disable if specific property not set
}/**
* Filters endpoints based on custom criteria
* @param <E> Type of exposable endpoint
*/
@FunctionalInterface
public interface EndpointFilter<E extends ExposableEndpoint<?>> {
/**
* Tests if an endpoint should be included
* @param endpoint The endpoint to test
* @return true if endpoint should be included, false otherwise
*/
boolean match(E endpoint);
}
/**
* Resolves endpoint access levels from configuration
*/
public interface EndpointAccessResolver {
/**
* Determines the access level for an endpoint
* @param endpointId The endpoint identifier
* @param defaultAccess The default access level
* @return The resolved access level
*/
Access accessFor(EndpointId endpointId, Access defaultAccess);
}
/**
* Contributes information to the info endpoint
*/
public interface InfoContributor {
/**
* Contributes information to the info endpoint
* @param builder The info builder
*/
void contribute(Info.Builder builder);
}
/**
* Maps parameter values from strings to required types
* Used when invoking endpoint operations via web or JMX
*/
public interface ParameterValueMapper {
/**
* Maps a parameter value to the required type
* @param parameter Operation parameter metadata
* @param value String value from request (may be null)
* @return Converted value
* @throws ParameterMappingException if conversion fails
*/
Object mapParameterValue(OperationParameter parameter, @Nullable Object value)
throws ParameterMappingException;
}
/**
* 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);
}
/**
* Invokes an endpoint operation
*/
@FunctionalInterface
public interface OperationInvoker {
/**
* Invokes the operation
* @param context The invocation context
* @return The operation result
*/
Object invoke(InvocationContext context);
}
/**
* Applies caching behavior to endpoint operations
*/
public interface CachingOperationInvokerAdvisor {
/**
* Applies caching to an operation invoker
* @param endpointId Endpoint ID
* @param operationType Operation type (READ, WRITE, DELETE)
* @param parameters Operation parameters
* @param invoker Original invoker
* @return Wrapped invoker with caching
*/
OperationInvoker apply(
EndpointId endpointId,
OperationType operationType,
OperationParameters parameters,
OperationInvoker invoker
);
}
/**
* Provides endpoint identifier
*/
public interface EndpointIdProvider {
/**
* Gets the endpoint ID
* @return The endpoint ID
*/
EndpointId getEndpointId();
}
/**
* 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();
}
/**
* Creates JMX object names for endpoints
*/
public interface EndpointObjectNameFactory {
/**
* Gets the JMX ObjectName for an endpoint
* @param endpoint The JMX endpoint
* @return The ObjectName
* @throws MalformedObjectNameException if the name is invalid
*/
ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException;
}
/**
* Contributes to endpoint exposure outcome determination
* @since 3.4.0
*/
public interface EndpointExposureOutcomeContributor {
/**
* Gets the exposure outcome for an endpoint
* @param endpointId The endpoint ID
* @param exposures The exposure technologies
* @param message Message builder for logging
* @return The condition outcome, or null to continue evaluation
*/
@Nullable
ConditionOutcome getExposureOutcome(
EndpointId endpointId,
Set<EndpointExposure> exposures,
ConditionMessage.Builder message
);
}/**
* Represents an endpoint identifier
* Immutable, normalized representation of an endpoint ID
*/
public final class EndpointId {
/**
* Creates an endpoint ID from a string value
* @param value The endpoint ID value (e.g., "health", "custom-endpoint")
* @return The endpoint ID
* @throws IllegalArgumentException if value is invalid
*/
public static EndpointId of(String value);
/**
* Creates an endpoint ID from a property value
* Normalizes the value (e.g., converts kebab-case/snake_case to lowercase)
* @param value The property value
* @return The endpoint ID
*/
public static EndpointId fromPropertyValue(String value);
/**
* Returns the string representation of this endpoint ID
* @return The endpoint ID as a string
*/
@Override
public String toString();
/**
* Returns the lower-case string representation of this endpoint ID
* @return The endpoint ID as a lower-case string
*/
public String toLowerCaseString();
/**
* Compares this endpoint ID to another object
* @param obj The object to compare
* @return true if equal
*/
@Override
public boolean equals(Object obj);
/**
* Returns the hash code for this endpoint ID
* @return The hash code
*/
@Override
public int hashCode();
}
/**
* Context for operation invocation
*/
public interface InvocationContext {
/**
* Gets the operation arguments
* @return Map of argument names to values
*/
Map<String, Object> getArguments();
/**
* Gets the security context
* @return The security context
*/
SecurityContext getSecurityContext();
}
/**
* Exception thrown when parameter mapping fails
*/
public class ParameterMappingException extends RuntimeException {
public ParameterMappingException(String message, Throwable cause);
}
/**
* 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
* @return Produced media types
*/
public List<String> getProduced();
/**
* Gets media types consumed by endpoints
* @return Consumed media types
*/
public List<String> getConsumed();
}
/**
* Collection of all path-mapped endpoints
*/
public class PathMappedEndpoints implements Iterable<PathMappedEndpoint> {
/**
* Gets the base path for all endpoints
* @return Base path (e.g., "/actuator")
*/
public String getBasePath();
/**
* Gets root path for endpoint with given ID
* @param endpointId Endpoint ID
* @return Root path or null if not found
*/
public String getRootPath(EndpointId endpointId);
/**
* Gets full path for endpoint with given ID
* @param endpointId Endpoint ID
* @return Full path (base path + root path) or null if not found
*/
public String getPath(EndpointId endpointId);
/**
* Gets endpoint by ID
* @param endpointId Endpoint ID
* @return PathMappedEndpoint or null if not found
*/
public PathMappedEndpoint getEndpoint(EndpointId endpointId);
/**
* Gets all root paths (excluding additional paths)
* @return Collection of root paths
*/
public Collection<String> getAllRootPaths();
/**
* Gets all full paths (excluding additional paths)
* @return Collection of full paths
*/
public Collection<String> getAllPaths();
/**
* Gets additional paths for given endpoint
* @param webServerNamespace Web server namespace
* @param endpointId Endpoint ID
* @return Collection of additional paths
* @since 3.4.0
*/
public Collection<String> getAdditionalPaths(WebServerNamespace webServerNamespace, EndpointId endpointId);
/**
* Streams all path-mapped endpoints
* @return Stream of endpoints
*/
public Stream<PathMappedEndpoint> stream();
/**
* Returns an iterator over path-mapped endpoints
* @return Iterator of endpoints
*/
@Override
public Iterator<PathMappedEndpoint> iterator();
}
/**
* Web operation request predicate
*/
public class WebOperationRequestPredicate {
private final String path;
private final WebEndpointHttpMethod httpMethod;
private final Collection<String> consumes;
private final Collection<String> produces;
/**
* Gets the operation path
* @return The path
*/
public String getPath();
/**
* Gets the HTTP method
* @return The HTTP method
*/
public WebEndpointHttpMethod getHttpMethod();
/**
* Gets the consumed media types
* @return Consumed media types
*/
public Collection<String> getConsumes();
/**
* Gets the produced media types
* @return Produced media types
*/
public Collection<String> getProduces();
}
/**
* HTTP methods for web operations
*/
public enum WebEndpointHttpMethod {
GET,
POST,
DELETE
}@Configuration
public class ActuatorSecurityConfiguration {
@Bean
public SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.to("metrics", "prometheus")).hasRole("METRICS")
.anyRequest().hasRole("ACTUATOR"))
.httpBasic(Customizer.withDefaults());
return http.build();
}
}# Client configuration
spring.boot.admin.client.url=http://admin-server:8080
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=alwaysmanagement.endpoints.web.exposure.include=health,prometheus
management.metrics.export.prometheus.enabled=true@Configuration
public class MetricsConfiguration {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "my-app", "region", "us-east");
}
}Breaking changes:
Jackson 2 → Jackson 3: Update to Jackson 3 (Jackson 2 support deprecated)
<!-- Update dependency -->
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>enabled → access: Migrate from .enabled to .access properties
# OLD (deprecated)
management.endpoint.health.enabled=true
# NEW
management.endpoint.health.access=UNRESTRICTED@ControllerEndpoint/@ServletEndpoint: Migrate to @Endpoint with extensions
// OLD (deprecated since 3.3.0, scheduled for removal)
@ControllerEndpoint(id = "custom")
// NEW
@Endpoint(id = "custom")
@WebEndpoint@Bean
public EndpointFilter<ExposableWebEndpoint> customFilter() {
return endpoint -> {
// Custom filtering logic
return !endpoint.getEndpointId().toString().startsWith("internal");
};
}@Bean
public EndpointAccessResolver customAccessResolver() {
return (endpointId, defaultAccess) -> {
if (endpointId.toString().equals("shutdown")) {
return Access.NONE;
}
return defaultAccess;
};
}@Bean
public PathMapper customPathMapper() {
return endpointId -> {
String id = endpointId.toString();
return switch (id) {
case "health" -> "status";
case "info" -> "about";
default -> id;
};
};
}// Register in META-INF/spring/...EndpointExposureOutcomeContributor.imports
public class CustomExposureContributor implements EndpointExposureOutcomeContributor {
@Override
public ConditionOutcome getExposureOutcome(EndpointId id, Set<EndpointExposure> exposures, ConditionMessage.Builder message) {
// Custom exposure logic
return null; // or ConditionOutcome
}
}# Enable caching for expensive endpoints
management.endpoint.beans.cache.time-to-live=10s
management.endpoint.conditions.cache.time-to-live=30s
management.endpoint.mappings.cache.time-to-live=60s# Limit recording to reduce memory
management.httpexchanges.recording.include=TIME_TAKEN
# Default capacity: 100 entries
# Memory: ~1KB per exchangeWhen using separate management port:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class CustomEndpointTest {
@LocalManagementPort
private int managementPort;
@Autowired
private TestRestTemplate restTemplate;
@Test
void customEndpointReturnsData() {
String url = "http://localhost:" + managementPort + "/actuator/custom";
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}@SpringBootTest(properties = {
"management.endpoint.custom.access=UNRESTRICTED",
"management.endpoints.web.exposure.include=custom"
})
class EndpointAvailabilityTest {
@Autowired
private ApplicationContext context;
@Test
void customEndpointIsRegistered() {
assertThat(context.containsBean("customEndpoint")).isTrue();
}
}Understanding how the subsystems work together:
Application Startup
↓
1. Core Infrastructure Setup
→ [core-infrastructure.md](./core-infrastructure.md)
- EndpointAutoConfiguration creates parameter mappers, caching, access resolvers
- PropertiesEndpointAccessResolver reads access properties
↓
2. Endpoint Discovery & Registration
→ [management-endpoints.md](./management-endpoints.md)
- Individual endpoint auto-configurations register endpoint beans
- @ConditionalOnAvailableEndpoint checks exposure/access via [conditional-annotations.md](./conditional-annotations.md)
↓
3. Endpoint Filtering
→ [endpoint-filtering.md](./endpoint-filtering.md)
- IncludeExcludeEndpointFilter applies include/exclude patterns
- EndpointExposureOutcomeContributor (SPI) provides custom logic
↓
4. Exposure Configuration
→ [web-endpoints.md](./web-endpoints.md) | [jmx-endpoints.md](./jmx-endpoints.md)
- WebEndpointAutoConfiguration exposes via HTTP
- JmxEndpointAutoConfiguration exposes via JMX MBeans
- PathMapper maps endpoint IDs to URL paths
↓
5. Management Server Setup (Optional)
→ [management-server.md](./management-server.md)
- ManagementContextAutoConfiguration creates separate server if configured
- Separate port with independent SSL, thread pool, and context
↓
6. Endpoint Configuration
→ [endpoint-properties.md](./endpoint-properties.md)
- Endpoint-specific properties applied (show-values, roles, recording, etc.)
↓
7. Runtime Operation
- Incoming request → PathMappedEndpoints → WebOperation
- OperationFilter applies access control
- ParameterValueMapper converts parameters
- CachingOperationInvokerAdvisor caches if configured
- Operation invoked → Response returnedStarting Point → Related Documents → Purpose
| If You Need To... | Start Here | Then Check | Finally See |
|---|---|---|---|
| Configure endpoint exposure | web-endpoints.md | endpoint-filtering.md | conditional-annotations.md |
| Secure endpoints | core-infrastructure.md (Access Control) | endpoint-filtering.md (Filtering) | web-endpoints.md (CORS) |
| Create custom endpoint | management-endpoints.md (Examples) | core-infrastructure.md (Infrastructure) | web-endpoints.md (Exposure) |
| Separate management port | management-server.md | web-endpoints.md (Properties) | endpoint-properties.md (SSL Config) |
| Control access per-endpoint | core-infrastructure.md (Access Resolver) | endpoint-properties.md (Per-endpoint props) | endpoint-filtering.md (Operation filters) |
| Configure JMX exposure | jmx-endpoints.md | endpoint-filtering.md (Include/exclude) | conditional-annotations.md (@ConditionalOn...) |
| Debug why endpoint not available | endpoint-filtering.md (Filtering logic) | conditional-annotations.md (Conditions) | core-infrastructure.md (Access levels) |
| Configure CORS for endpoints | web-endpoints.md (CORS section) | endpoint-properties.md (Properties) | - |
Shows which documents cover interactions between components:
| Component A | Component B | Interaction Documented In |
|---|---|---|
| EndpointAutoConfiguration | WebEndpointAutoConfiguration | core-infrastructure.md, web-endpoints.md |
| IncludeExcludeEndpointFilter | @ConditionalOnAvailableEndpoint | endpoint-filtering.md, conditional-annotations.md |
| WebEndpointProperties | PathMapper | web-endpoints.md |
| ManagementServerProperties | ManagementContextAutoConfiguration | management-server.md |
| PropertiesEndpointAccessResolver | EndpointFilter | core-infrastructure.md, endpoint-filtering.md |
| Individual Endpoints | InfoContributor | management-endpoints.md |
| CorsEndpointProperties | WebEndpointAutoConfiguration | web-endpoints.md, endpoint-properties.md |
| Problem | Check These Docs (In Order) |
|---|---|
| Endpoint returns 404 | 1. endpoint-filtering.md (exposure)<br>2. web-endpoints.md (path mapping)<br>3. management-server.md (port) |
| Endpoint shows wrong values | 1. endpoint-properties.md (show-values)<br>2. management-endpoints.md (endpoint config) |
| Cannot write to endpoint | 1. core-infrastructure.md (access levels)<br>2. endpoint-filtering.md (operation filters) |
| CORS errors | 1. web-endpoints.md (CORS config)<br>2. endpoint-properties.md (properties) |
| Custom endpoint not registered | 1. conditional-annotations.md (conditions)<br>2. endpoint-filtering.md (filtering)<br>3. management-endpoints.md (registration) |
| Management port conflict | 1. management-server.md (port config)<br>2. web-endpoints.md (base path) |
Detailed subsystem documentation (see Subsystems Reference above):
Related Spring Boot and monitoring ecosystem: