Backend Development 6 min read

Monitor Spring Boot API Latency with Actuator, AOP, and Prometheus

This tutorial shows how to instrument Spring Boot APIs using Actuator, a custom @Monitor annotation with AOP, and Prometheus to collect and visualize method execution times, providing a complete end‑to‑end monitoring solution.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Monitor Spring Boot API Latency with Actuator, AOP, and Prometheus

1. Introduction

This article explains how to monitor arbitrary API call latency in a Spring Boot application by combining Spring Boot Actuator, a custom @Monitor annotation, AOP, and Prometheus.

2. Environment Setup

Required dependencies:

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  &lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;io.micrometer&lt;/groupId&gt;
  &lt;artifactId&gt;micrometer-registry-prometheus&lt;/artifactId&gt;
  &lt;scope&gt;runtime&lt;/scope&gt;
&lt;/dependency&gt;</code>

Expose all actuator endpoints:

<code>management:
  endpoints:
    web:
      base-path: /ac
      exposure:
        include: '*'</code>

3. Practical Example

3.1 Define the @Monitor annotation

<code>@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Monitor {
  String[] tags() default {};
}</code>

3.2 Implement the monitoring aspect

<code>@Component
@Aspect
public class MonitorAspect {
  private final MeterRegistry meterRegistry;
  private static final String API_TIMER_METER_NAME = "myapp.api.timer";

  public MonitorAspect(MeterRegistry meterRegistry) {
    this.meterRegistry = meterRegistry;
  }

  @Pointcut("@annotation(monitor)")
  private void pcMonitor(Monitor monitor) {}

  @Around("pcMonitor(monitor)")
  public Object around(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
    Timer.Sample sample = Timer.start(this.meterRegistry);
    String[] tags = monitor.tags();
    Object ret = null;
    Throwable ex = null;
    try {
      ret = pjp.proceed();
    } catch (Throwable th) {
      ex = th;
      throw th;
    } finally {
      List<String> listTags = new ArrayList<>();
      listTags.addAll(Arrays.asList(tags));
      if (Objects.nonNull(ex)) {
        listTags.add(ex.getClass().getSimpleName());
      }
      Timer timer = meterRegistry.timer(API_TIMER_METER_NAME, listTags.toArray(new String[0]));
      sample.stop(timer);
    }
    return ret;
  }
}</code>

3.3 Service layer

<code>@Service
public class UserService {
  private static final List<User> DATAS = List.of(
      new User(1L, "张三", "男", 22),
      new User(2L, "李四", "男", 23),
      new User(3L, "王五", "女", 22),
      new User(4L, "赵六", "男", 32));

  public List<User> queryUsers() {
    sleep(2000);
    return DATAS;
  }

  public User queryById(Long id) {
    sleep(1000);
    return DATAS.stream().filter(user -> user.getId() == id).findFirst().orElse(null);
  }

  private void sleep(int time) {
    try {
      TimeUnit.MILLISECONDS.sleep(new Random().nextInt(time));
    } catch (InterruptedException e) {}
  }
}</code>

3.4 Controller layer

<code>@Monitor(tags = {"UserController", "list"})
@GetMapping("")
public List<User> list() {
  return this.userService.queryUsers();
}

@Monitor(tags = {"UserController", "ById"})
@GetMapping("/{id}")
public User queryById(@PathVariable Long id) {
  return this.userService.queryById(id);
}</code>

Note: The tags attribute must contain an even number of strings because they are paired as key/value tags.

4. Testing and Visualization

Invoke the two endpoints repeatedly and access /ac/metrics/myapp.api.timer to view raw metrics. Prometheus scrapes the /actuator/prometheus endpoint, and you can visualize latency trends in Grafana or the Prometheus UI.

monitoringAOPBackend DevelopmentPrometheusSpring BootActuator
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.