
Spring Boot Actuator Endpoints – Monitoring Your Application
Spring Boot Actuator provides production-ready features for monitoring and managing your applications through HTTP endpoints and JMX beans. These endpoints expose crucial information about your application’s health, metrics, configuration, and runtime behavior – making it indispensable for production deployments where visibility into application performance is critical. This guide walks you through setting up, configuring, and leveraging Spring Boot Actuator endpoints for comprehensive application monitoring, covering security considerations, custom endpoint creation, and integration with external monitoring systems.
How Spring Boot Actuator Works
Spring Boot Actuator operates by auto-configuring a set of endpoints that expose operational information about your running application. When you include the actuator dependency, Spring Boot automatically registers these endpoints and makes them available through HTTP or JMX. The framework uses conditional configuration to determine which endpoints to enable based on your application’s dependencies and configuration properties.
Under the hood, Actuator uses Spring MVC or Spring WebFlux to create REST endpoints, depending on your application type. Each endpoint is implemented as a Spring component that collects and returns specific operational data. The health endpoint, for example, aggregates status information from various health indicators like database connections, disk space, and custom health checks.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Step-by-Step Implementation Guide
Setting up Spring Boot Actuator requires minimal configuration, but proper setup involves security considerations and endpoint customization. Here’s a comprehensive implementation approach:
Step 1: Add Dependencies and Basic Configuration
# application.properties
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoints.web.base-path=/actuator
management.endpoint.health.show-details=when-authorized
management.endpoint.health.show-components=always
management.info.env.enabled=true
Step 2: Configure Security
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(requests ->
requests.requestMatchers("/actuator/health/**").permitAll()
.requestMatchers("/actuator/info").permitAll()
.anyRequest().hasRole("ADMIN"))
.httpBasic(withDefaults())
.build();
}
}
Step 3: Create Custom Health Indicators
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection connection = dataSource.getConnection()) {
if (connection.isValid(1)) {
return Health.up()
.withDetail("database", "Available")
.withDetail("validationQuery", "SELECT 1")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("database", "Unavailable")
.withException(e)
.build();
}
return Health.down().build();
}
}
Step 4: Add Custom Metrics
@RestController
public class OrderController {
private final MeterRegistry meterRegistry;
private final Counter orderCounter;
private final Timer orderProcessingTime;
public OrderController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCounter = Counter.builder("orders.created")
.description("Number of orders created")
.register(meterRegistry);
this.orderProcessingTime = Timer.builder("orders.processing.time")
.description("Order processing time")
.register(meterRegistry);
}
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody Order order) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
// Process order
Order savedOrder = orderService.save(order);
orderCounter.increment();
return ResponseEntity.ok(savedOrder);
} finally {
sample.stop(orderProcessingTime);
}
}
}
Key Actuator Endpoints and Their Uses
Endpoint | Purpose | Production Safe | Common Use Case |
---|---|---|---|
/health | Application health status | Yes | Load balancer health checks |
/metrics | Application metrics and counters | With auth | Performance monitoring |
/info | Application information | Yes | Version and build info |
/env | Environment properties | No | Configuration debugging |
/loggers | View and modify logging levels | With auth | Runtime log level adjustment |
/threaddump | Thread dump information | No | Performance troubleshooting |
/heapdump | Heap dump file | No | Memory leak analysis |
Real-World Use Cases and Examples
Load Balancer Integration
Most production deployments integrate the health endpoint with load balancers for automatic failover. Here’s how to configure a detailed health check that considers multiple dependencies:
management.endpoint.health.group.readiness.include=db,redis,external-service
management.endpoint.health.group.readiness.show-details=always
management.endpoint.health.group.liveness.include=ping
management.endpoint.health.group.liveness.show-details=always
Prometheus Integration for Metrics Collection
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
# application.properties
management.endpoints.web.exposure.include=prometheus
management.metrics.export.prometheus.enabled=true
management.metrics.distribution.percentiles-histogram.http.server.requests=true
Custom Info Endpoint with Git Information
@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("app", Map.of(
"name", "Order Management System",
"version", "2.1.0",
"environment", System.getProperty("spring.profiles.active", "default")
));
builder.withDetail("features", List.of(
"payment-processing",
"inventory-management",
"customer-notifications"
));
}
}
Graceful Shutdown Configuration
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s
management.endpoint.shutdown.enabled=true
Comparison with Alternative Monitoring Solutions
Feature | Spring Boot Actuator | Micrometer + Prometheus | New Relic | Application Insights |
---|---|---|---|---|
Setup Complexity | Very Low | Medium | Low | Low |
Cost | Free | Free (self-hosted) | Paid | Paid |
Custom Metrics | Yes | Excellent | Yes | Yes |
Alerting | No | With Alertmanager | Built-in | Built-in |
Distributed Tracing | Basic | With Jaeger/Zipkin | Yes | Yes |
Spring Boot Actuator excels as a foundation for application monitoring, especially when you need basic health checks and metrics without external dependencies. For comprehensive monitoring solutions, combining Actuator with Prometheus and Grafana provides enterprise-level capabilities while maintaining cost effectiveness, particularly for applications running on VPS or dedicated servers.
Best Practices and Common Pitfalls
Security Best Practices
- Never expose sensitive endpoints like /env, /configprops, or /heapdump in production without authentication
- Use different management ports for internal monitoring tools
- Implement IP-based access control for actuator endpoints
- Sanitize sensitive information in health details and info endpoints
# Separate management port configuration
management.server.port=8081
management.server.address=127.0.0.1
Performance Considerations
- Health checks should complete within 1-2 seconds to avoid load balancer timeouts
- Avoid expensive operations in health indicators – use cached results when possible
- Configure appropriate timeouts for external service health checks
- Monitor the performance impact of metrics collection, especially high-cardinality metrics
@Component
public class ExternalServiceHealthIndicator implements HealthIndicator {
private final WebClient webClient;
private volatile Health cachedHealth = Health.up().build();
private volatile long lastCheck = 0;
private static final long CACHE_DURATION = 30000; // 30 seconds
@Override
public Health health() {
long now = System.currentTimeMillis();
if (now - lastCheck > CACHE_DURATION) {
updateHealthStatus();
lastCheck = now;
}
return cachedHealth;
}
private void updateHealthStatus() {
try {
String response = webClient.get()
.uri("/health")
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(2))
.block();
cachedHealth = Health.up().withDetail("response", "OK").build();
} catch (Exception e) {
cachedHealth = Health.down().withException(e).build();
}
}
}
Common Configuration Mistakes
- Exposing all endpoints by default using management.endpoints.web.exposure.include=*
- Not configuring proper health check groups for Kubernetes readiness/liveness probes
- Ignoring actuator endpoint performance in high-traffic applications
- Failing to customize sensitive data exposure in production environments
Monitoring Integration Pattern
# Docker health check integration
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
Advanced Custom Endpoint Example
@Component
@Endpoint(id = "database-stats")
public class DatabaseStatsEndpoint {
@Autowired
private DataSource dataSource;
@ReadOperation
public Map<String, Object> databaseStats() {
Map<String, Object> stats = new HashMap<>();
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData metaData = conn.getMetaData();
stats.put("databaseProductName", metaData.getDatabaseProductName());
stats.put("databaseProductVersion", metaData.getDatabaseProductVersion());
stats.put("driverName", metaData.getDriverName());
stats.put("maxConnections", metaData.getMaxConnections());
// Add connection pool stats if using HikariCP
if (dataSource instanceof HikariDataSource) {
HikariDataSource hikari = (HikariDataSource) dataSource;
HikariPoolMXBean pool = hikari.getHikariPoolMXBean();
stats.put("activeConnections", pool.getActiveConnections());
stats.put("idleConnections", pool.getIdleConnections());
stats.put("totalConnections", pool.getTotalConnections());
stats.put("threadsAwaitingConnection", pool.getThreadsAwaitingConnection());
}
} catch (SQLException e) {
stats.put("error", e.getMessage());
}
return stats;
}
}
Spring Boot Actuator transforms application monitoring from complex custom implementations to standardized, production-ready endpoints. The key to successful implementation lies in understanding the security implications, properly configuring health checks for your infrastructure, and leveraging custom metrics to gain insights specific to your application’s business logic. When deployed correctly on robust infrastructure, Actuator endpoints provide the foundation for comprehensive application observability that scales with your monitoring needs.
For additional configuration options and advanced features, consult the official Spring Boot Actuator documentation and the Micrometer metrics documentation for detailed metrics integration patterns.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.