java 61 lines · 7 steps

Building a custom Spring Boot Actuator endpoint

A custom @Endpoint exposes build and Git metadata over Actuator, with a selector variant for querying single fields.

Explained by highlit
1package com.example.actuator;
2 
3import org.springframework.beans.factory.annotation.Value;
4import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
5import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
6import org.springframework.boot.actuate.endpoint.annotation.Selector;
7import org.springframework.boot.info.BuildProperties;
8import org.springframework.boot.info.GitProperties;
9import org.springframework.stereotype.Component;
10 
11import java.time.Instant;
12import java.util.LinkedHashMap;
13import java.util.Map;
14 
15@Component
16@Endpoint(id = "release")
17public class ReleaseEndpoint {
18 
19 private final BuildProperties build;
20 private final GitProperties git;
21 private final String activeProfiles;
22 
23 public ReleaseEndpoint(BuildProperties build, GitProperties git,
24 @Value("${spring.profiles.active:default}") String activeProfiles) {
25 this.build = build;
26 this.git = git;
27 this.activeProfiles = activeProfiles;
28 }
29 
30 @ReadOperation
31 public Map<String, Object> release() {
32 Map<String, Object> app = new LinkedHashMap<>();
33 app.put("name", build.getName());
34 app.put("version", build.getVersion());
35 app.put("artifact", build.getArtifact());
36 app.put("buildTime", build.getTime());
37 app.put("profiles", activeProfiles);
38 
39 Map<String, Object> scm = new LinkedHashMap<>();
40 scm.put("branch", git.getBranch());
41 scm.put("commit", git.getShortCommitId());
42 scm.put("commitTime", git.getCommitTime());
43 scm.put("dirty", Boolean.parseBoolean(git.get("dirty")));
44 
45 Map<String, Object> payload = new LinkedHashMap<>();
46 payload.put("application", app);
47 payload.put("git", scm);
48 payload.put("reportedAt", Instant.now());
49 return payload;
50 }
51 
52 @ReadOperation
53 public Object releaseDetail(@Selector String key) {
54 return switch (key) {
55 case "version" -> build.getVersion();
56 case "commit" -> git.getCommitId();
57 case "branch" -> git.getBranch();
58 default -> Map.of("error", "unknown key: " + key);
59 };
60 }
61}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1@Endpoint plus @ReadOperation registers a custom Actuator endpoint reachable over HTTP or JMX.
  2. 2Spring Boot auto-populates BuildProperties and GitProperties from build-time metadata files.
  3. 3A @Selector parameter lets one endpoint serve both a full report and single-field lookups.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
python
import time
import uuid
 
from django.utils.deprecation import MiddlewareMixin

Attaching per-request context in Django

middleware request lifecycle multi-tenancy
Intermediate 7 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
java
package com.acme.billing.config;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;

Feature-flagged beans with Spring @ConditionalOnProperty

feature-flags conditional-beans strategy-pattern
Intermediate 5 steps

Share this explainer

Here's the card — post it anywhere.

Building a custom Spring Boot Actuator endpoint — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code