Create your own
Lesson illustration

Spring Boot Actuator: Implementing Health Checks

Hello! Welcome back to our course on preparing for microservices interviews.

In our last lesson, we covered strategies for migrating from a monolith, including the Strangler Fig pattern. Once you've successfully extracted a new, independent microservice, a critical question arises: "How do we know if this new service is actually working?" In a distributed system with dozens or even hundreds of services, you can't manually check each one. We need an automated, reliable way to monitor their health.

This lesson addresses that fundamental need. We'll explore how to implement health checks, a cornerstone of building observable and resilient, production-ready applications. This capability is essential for everything from load balancers that need to know where to send traffic, to container orchestrators like Kubernetes that automatically restart failing services. For your interview preparation, demonstrating a solid grasp of health monitoring is non-negotiable.

By the end of this lesson, you will be able to implement health check endpoints using Spring Boot Actuator for service monitoring.

1. What is Service Health and Why Does It Matter?

Before diving into the code, let's clarify what "health" means in a microservices context. It's more than just "is the process running?". A service might be running but unable to function correctly. For example, it could have run out of database connections or lost connectivity to a critical downstream API.

In a distributed architecture, other systems need to know the state of your service to make intelligent decisions.

Health Monitoring in Microservice explained with Spring Boot

This video, 'Health Monitoring in Microservice explained', gives an excellent overview of the core concepts. It explains how health checks are used by schedulers and orchestrators to prevent cascading failures.

Watch the first 54 seconds of this video. Focus on the idea that health checks are signals that services send to the wider system to report their status, enabling the system to react to failures automatically.

This automated feedback loop is what allows a complex system to be self-healing and resilient. Spring Boot provides a powerful tool out-of-the-box to build these health endpoints: Spring Boot Actuator.

2. Getting Started with Spring Boot Actuator

Spring Boot Actuator is a sub-project that brings production-ready features to your application. When you include it, you get a set of endpoints that expose operational information about your running application—health, metrics, environment info, and much more.

Let's see how to enable it and access the basic health endpoint.

Mastering Spring Boot Actuator: Monitoring & Managing Your Application

The video 'Mastering Spring Boot Actuator' provides a great hands-on introduction. We'll watch a few short clips to see the setup process.

Watch from 02:31 to 04:28. This will show you two things: How to add the spring-boot-starter-actuator dependency to your pom.xml. How to access the default /actuator/health endpoint and what its minimal response looks like.

As you saw, just by adding one dependency, you get a working /actuator/health endpoint. By default, it returns a simple {"status":"UP"} with a 200 OK HTTP status. If the application fails to start, this endpoint won't be available.

Exposing Detailed Information

For security reasons, Spring Boot only exposes the /health endpoint by default. For development and debugging, it's useful to expose all the available endpoints. You can do this by adding the following property to your application.properties or application.yml file:

application.properties:

management.endpoints.web.exposure.include=*

application.yml:

management:
  endpoints:
    web:
      exposure:
        include: "*"

Warning: Exposing all endpoints with * is great for learning but can be a security risk in production, as endpoints like /env and /heapdump can leak sensitive information. In a real production environment, you would selectively expose only the endpoints you need (e.g., health,info,metrics,prometheus).

Let's see the rich information you can get once you expose more endpoints.

Mastering Spring Boot Actuator: Monitoring & Managing Your Application

Let's return to the 'Mastering Spring Boot Actuator' video to explore the other endpoints that become available.

Watch from 06:10 to 14:11. You don't need to memorize every endpoint, but pay attention to the purpose of these key ones: /beans: Shows all the beans in your Spring context. /env: Displays all environment properties. /metrics: Provides a wide range of metrics like JVM memory, CPU usage, etc. /threaddump: Gives a snapshot of all running threads, which is invaluable for debugging deadlocks.

3. Implementing Custom Health Checks

The default health check is a good start, but a truly robust service must also verify the health of its dependencies. If your OrderService can't connect to the PaymentService or the database, it's not truly "healthy," even if its own process is running.

Spring Boot Actuator automatically provides Health Indicators for common components like databases (JPA), message brokers (RabbitMQ, Kafka), and caches (Redis) if they are on the classpath. When you visit /actuator/health, Actuator aggregates the status of all registered indicators. If any one of them reports "DOWN," the overall status becomes "DOWN."

But what about dependencies that Spring Boot doesn't know about, like a third-party REST API? For this, we need to create a custom health indicator.

This is done by creating a Spring bean that implements the HealthIndicator interface.

Adding Health Checks to Spring Boot with Custom Indicators

The article 'Adding Health Checks to Spring Boot with Custom Indicators' provides a fantastic walkthrough of this process. It explains the core interface and shows a clear, practical example.

Read the sections 'The HealthIndicator Interface' and 'Building and Registering Custom Health Indicators'. Focus on: The structure of the HealthIndicator interface and its single health() method. How the Health.up() and Health.down() builders are used to construct the response. The example code for PingServiceHealthIndicator, which checks a dependency and reports its status.

Let's solidify this with an example. Imagine our microservice depends on an external service for fraud detection. Here’s how we could write a health indicator for it.

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component("fraudService") // The bean name ("fraudService") becomes the key in the JSON response
public class FraudServiceHealthIndicator implements HealthIndicator {

    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public Health health() {
        try {
            // Assume the fraud service has a health endpoint at this URL
            String fraudServiceUrl = "http://api.external-fraud.com/health";
            
            // A simple check: if we get a 2xx response, it's up.
            restTemplate.getForEntity(fraudServiceUrl, String.class);

            return Health.up()
                         .withDetail("service", "Fraud Detection Service")
                         .withDetail("url", fraudServiceUrl)
                         .build();
        } catch (Exception e) {
            // If the call fails for any reason (timeout, 5xx error, etc.)
            return Health.down()
                         .withDetail("service", "Fraud Detection Service")
                         .withError(e) // Attaching the exception is good for diagnostics
                         .build();
        }
    }
}

With this bean in your application context, the response from /actuator/health (assuming you've configured management.endpoint.health.show-details=always) would now include a section for your custom check:

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": { ... }
    },
    "fraudService": {
      "status": "UP",
      "details": {
        "service": "Fraud Detection Service",
        "url": "http://api.external-fraud.com/health"
      }
    },
    "diskSpace": { ... },
    "ping": { ... }
  }
}
Test your understanding!

Your microservice needs to read files from a specific directory on the server's file system (e.g., /var/data/uploads). If this directory is not readable or doesn't exist, the service cannot function.

How would you implement a custom HealthIndicator to check for the existence and readability of this directory?

Show answer

You would create a new class that implements HealthIndicator and use Java's java.io.File API to perform the check.

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.io.File;

@Component
public class UploadsDirHealthIndicator implements HealthIndicator {

    private static final String UPLOADS_DIR_PATH = "/var/data/uploads";

    @Override
    public Health health() {
        try {
            File uploadsDir = new File(UPLOADS_DIR_PATH);
            if (uploadsDir.exists() && uploadsDir.canRead()) {
                return Health.up()
                             .withDetail("path", UPLOADS_DIR_PATH)
                             .withDetail("status", "Exists and is readable")
                             .build();
            } else {
                return Health.down()
                             .withDetail("path", UPLOADS_DIR_PATH)
                             .withDetail("status", "Does not exist or is not readable")
                             .build();
            }
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}

The bean name will default to uploadsDirHealthIndicator, and it will be automatically included in the /actuator/health response.

4. Liveness vs. Readiness: A Critical Distinction

In containerized environments like Kubernetes (which we will cover in depth later), health checks are divided into two categories. This is a very common interview topic.

  1. Liveness Probe: "Is the application alive?" If this probe fails, Kubernetes assumes the application is deadlocked or broken and restarts the container.
  2. Readiness Probe: "Is the application ready to serve traffic?" If this probe fails, Kubernetes stops sending traffic to the container but leaves it running, assuming it might recover.

A service could be live but not ready. For example, it might be live during startup while it's warming up a cache or establishing initial database connections. You wouldn't want to restart it (it's not dead), but you also don't want to send it user traffic yet.

Spring Boot Actuator directly supports this distinction.

Adding Health Checks to Spring Boot with Custom Indicators

The article 'Adding Health Checks to Spring Boot' also covers this crucial concept and its implementation.

Read the section 'Readiness vs Liveness Checks'. Pay close attention to: The purpose of the two different probes. The configuration properties needed to enable them (management.health.probes.enabled=true). How to assign a specific health indicator to a group (e.g., readiness) in your application.yml.

Once enabled, Spring Boot exposes two more specific endpoints:

  • /actuator/health/liveness: Contains all health indicators not explicitly assigned to the readiness group.
  • /actuator/health/readiness: Contains only the health indicators assigned to the readiness group.

This powerful feature allows you to give fine-grained signals to your container orchestrator, leading to more stable and reliable deployments.

Conclusion

You've now learned how to make your microservices observable and production-ready by implementing robust health checks. This is a foundational skill for any microservices developer.

Key Takeaways:

  • Spring Boot Actuator provides essential production-ready features, with /actuator/health being central to monitoring.
  • Actuator automatically detects and checks common dependencies like databases and message brokers.
  • You can create custom HealthIndicator beans to check any internal or external dependency that your service relies on.
  • In containerized environments, distinguishing between Liveness (restart if failed) and Readiness (stop traffic if failed) probes is critical for zero-downtime operations.
  • Spring Boot provides /actuator/health/liveness and /actuator/health/readiness endpoints to support this pattern.

In an interview, when asked about service reliability or monitoring, you should confidently discuss your strategy using Actuator, custom health indicators, and the roles of liveness and readiness probes in a Kubernetes environment.

Next Up

A production-ready service not only needs to be observable but also correctly configured for different environments (development, staging, production). In our next lesson, we will dive into configuring application properties for different environments using Spring profiles.

Can't find a good explanation? Sign up and we'll make it for you

Sign up