Appearance
Spring Boot Actuator in Depth
The Automobile Dashboard Analogy
Imagine purchasing a high performance automobile that has no dashboard instruments: no speedometer, no fuel gauge, no engine temperature warning light, and no oil pressure monitor. The car still accelerates, steers, and brakes. But the driver operates completely blind. You cannot tell if the engine is overheating on the highway until smoke pours from the hood, and you cannot verify fuel levels until the engine stalls on an interstate bridge.
In software engineering, running Spring Boot in production without Spring Boot Actuator is driving that dashboardless automobile. Your REST endpoints may handle requests, but you have zero visibility into JVM memory utilization, database connection pool health, active thread counts, garbage collection pauses, or logging levels.
Spring Boot Actuator provides production grade, pre built management endpoints out of the box. It acts as the vehicle dashboard for your microservice, allowing operations teams, container orchestrators (Kubernetes), and monitoring platforms (Prometheus, Grafana, Datadog) to observe, audit, and interact with the application while it runs.
This lecture covers Actuator configuration, essential endpoints, writing custom HealthIndicator components, runtime log level mutation, and securing actuator endpoints in production.
Adding Spring Boot Actuator
Add the Actuator dependency to your pom.xml:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>When you start the application, Actuator automatically registers management endpoints under the base path /actuator.
The Essential Actuator Endpoints
By default, for security reasons, Spring Boot exposes only /actuator/health over HTTP. All other endpoints must be explicitly enabled and exposed in application.properties.
| Endpoint | Default Exposure | Purpose & Diagnostic Value |
|---|---|---|
/actuator/health | Enabled | Shows application health status (UP, DOWN). Used by Kubernetes liveness and readiness probes |
/actuator/info | Disabled | Displays arbitrary application information (build version, git commit hash, description) |
/actuator/metrics | Disabled | Exposes internal JVM, memory, GC, HTTP request, and thread metrics |
/actuator/env | Disabled | Exposes properties from Spring Environment, system properties, and environment variables |
/actuator/beans | Disabled | Displays a complete list of all Spring beans instantiated in the ApplicationContext |
/actuator/loggers | Disabled | Displays and modifies logging levels of specific packages at runtime without restarting |
/actuator/threaddump | Disabled | Generates an instantaneous JVM thread dump for diagnosing deadlocks and CPU spikes |
Configuring Endpoint Exposure in application.properties
You control which endpoints are exposed over HTTP using management.endpoints.web.exposure.include:
properties
server.port=8080
spring.application.name=order-service
# Expose specific management endpoints over HTTP
management.endpoints.web.exposure.include=health,info,metrics,loggers
# To expose all endpoints (strictly for local development, NEVER in production!):
# management.endpoints.web.exposure.include=*
# Change actuator base path if desired (default is /actuator)
management.endpoints.web.base-path=/actuator
# Show detailed health breakdown to authenticated clients
management.endpoint.health.show-details=alwaysDeep Dive: /actuator/health
When you visit http://localhost:8080/actuator/health, Actuator evaluates health indicators registered across the application:
json
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "PostgreSQL",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 499963174912,
"free": 321854218240,
"threshold": 10485760,
"path": "/var/log",
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}If even one critical component reports DOWN, the overall application status transitions to DOWN and Actuator returns an HTTP 503 Service Unavailable status code, signaling to Kubernetes to remove the pod from the load balancer.
Writing a Custom HealthIndicator
You can implement HealthIndicator to monitor your own critical dependencies (such as an external payment provider, search index, or local file buffer):
java
package com.example.orderservice.actuator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.net.HttpURLConnection;
import java.net.URL;
@Component
public class ExternalPaymentGatewayHealthIndicator implements HealthIndicator {
private static final String PAYMENT_GATEWAY_URL = "https://api.paymentprovider.example/health";
@Override
public Health health() {
try {
long latencyStart = System.currentTimeMillis();
boolean reachable = pingService(PAYMENT_GATEWAY_URL);
long latency = System.currentTimeMillis() - latencyStart;
if (reachable) {
return Health.up()
.withDetail("service", "External Payment Gateway")
.withDetail("latencyMs", latency)
.withDetail("endpoint", PAYMENT_GATEWAY_URL)
.build();
} else {
return Health.down()
.withDetail("service", "External Payment Gateway")
.withDetail("error", "Received non-200 response code")
.build();
}
} catch (Exception e) {
return Health.down(e)
.withDetail("service", "External Payment Gateway")
.withDetail("error", e.getMessage())
.build();
}
}
private boolean pingService(String urlStr) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(2000);
connection.setReadTimeout(2000);
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
return responseCode == 200;
}
}Now, /actuator/health includes an externalPaymentGateway entry with your live latency numbers.
Runtime Log Level Modification via /actuator/loggers
One of Actuator's most powerful operational capabilities is mutating logging levels on the fly without restarting the JVM.
Suppose your application runs in production with root log level INFO. A customer reports an intermittent order processing bug in package com.example.orderservice.service.
Inspect current logging level:
bashcurl http://localhost:8080/actuator/loggers/com.example.orderservice.serviceResponse:
json{"configuredLevel": "INFO", "effectiveLevel": "INFO"}Temporarily switch level to
DEBUGvia an HTTPPOST:bashcurl -X POST http://localhost:8080/actuator/loggers/com.example.orderservice.service -H "Content-Type: application/json" -d '{"configuredLevel": "DEBUG"}'The application immediately begins printing debug logs for that specific package.
Once the issue is diagnosed, switch it back to
INFOusing the same endpoint. Zero server restarts, zero downtime.
Production Security for Actuator
Exposing sensitive endpoints like /actuator/env or /actuator/threaddump publicly on the internet is a severe security vulnerability that leaks passwords, database URLs, and internal code structures.
Production Best Practices:
Run Actuator on a Dedicated Management Port:
properties# Application serves public customer traffic on port 8080 server.port=8080 # Management endpoints serve on private internal port 9090 management.server.port=9090Network firewalls block external traffic to port 9090, exposing it strictly to internal monitoring tools inside your private virtual cloud.
Secure with Spring Security: Require administrator credentials for sensitive actuator routes:
java@Bean public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher(EndpointRequest.toAnyEndpoint()) .authorizeHttpRequests(auth -> auth .requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll() .anyRequest().hasRole("ADMIN") ) .httpBasic(Customizer.withDefaults()); return http.build(); }
Interview Questions & Pitfalls
Q1: What is the primary purpose of Spring Boot Actuator?
Spring Boot Actuator provides production ready operational features out of the box, including health checks, JVM and system metrics collection, environment property inspection, thread dumps, and runtime configuration auditing. It allows operations teams and orchestration platforms (Kubernetes, Prometheus) to monitor and manage applications live.
Q2: Which actuator endpoint is enabled and exposed over HTTP by default in Spring Boot?
Only the /actuator/health endpoint is exposed over HTTP by default. All other endpoints are disabled or hidden by default to protect system security until explicitly included via management.endpoints.web.exposure.include.
Q3: How do you create a custom health check in Spring Boot?
Create a Spring @Component that implements the HealthIndicator interface and overrides the health() method. Inside the method, execute your custom verification logic and return Health.up().build() or Health.down().withDetail("reason", ...).build().
Q4: What is the security danger of setting management.endpoints.web.exposure.include=* in production?
Setting include=* exposes sensitive endpoints such as /actuator/env (which contains environment variables and configuration secrets), /actuator/beans (which exposes internal application architecture), and /actuator/threaddump to anyone who can reach the port. This leaks confidential infrastructure information and credentials.
Q5: How does Kubernetes use /actuator/health?
Kubernetes uses Actuator's health probes for container lifecycle management. The liveness probe (/actuator/health/liveness) verifies if the container is running; if it fails, Kubernetes restarts the pod. The readiness probe (/actuator/health/readiness) verifies if the container is ready to accept user traffic; if it fails, Kubernetes stops routing incoming requests to that pod until it recovers.