What do the @Timed and @Counted annotations do in a Micrometer/Spring Boot application?
answer
- @Timed -> Timer (duration+count), @Counted -> Counter
- auto tags: class, method, exception, (result)
- default names method.timed / method.counted
- handled by TimedAspect / CountedAspect via AOP
- @Timed on a class times every method
basics
~20 s@Timed records how long a method takes (a Timer metric); @Counted counts how many times it runs (a Counter). You put them on a method and Micrometer publishes the metric automatically, without writing timing code by hand.
solid answer
~40 s@Timed (io.micrometer.core.annotation.Timed) and @Counted are declarative Micrometer annotations that let you emit metrics without hand-writing instrumentation. @Timed creates a Timer that records the duration and count of a method's executions; @Counted creates a Counter that increments per invocation. Both automatically tag the metric with the class and method names, and add an 'exception' tag (and, for @Counted, a 'result' = success/failure tag). They are handled at runtime by Spring AOP aspects — TimedAspect and CountedAspect — which intercept the annotated method through a proxy, so the annotations only work on Spring-managed beans whose methods are invoked through the proxy. You can also put @Timed on a class to time every method. The metric name comes from the annotation's value attribute (defaults: method.timed / method.counted).
code
java · 18 linesimport io.micrometer.core.annotation.Counted;
import io.micrometer.core.annotation.Timed;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Timed(value = "orders.place", description = "Time to place an order")
public Order place(OrderRequest req) {
// ... work ...
return new Order();
}
@Counted(value = "orders.cancelled", recordFailuresOnly = false)
public void cancel(String orderId) {
// increments a counter tagged class/method/result/exception
}
}go deeper
Know that @Timed measures duration, @Counted counts calls, and both publish Micrometer meters automatically.
Know the automatic tags (class/method/exception/result) and the default metric names, plus that an aspect does the work.
Be able to explain the AOP proxy mechanism, when declarative beats imperative, and distribution attributes.
Frame declarative metrics within an observability strategy: cardinality, aggregation across instances, and consistency of naming/tagging conventions.
## What these annotations are Micrometer is the metrics facade used by Spring Boot Actuator (like SLF4J but for metrics). Normally you instrument code imperatively: obtain a `MeterRegistry`, build a `Timer`, and wrap the code in `timer.record(() -> ...)`. The **declarative** alternative is to annotate a method and let an aspect do the wrapping for you. - **`@Timed`** — `io.micrometer.core.annotation.Timed`. Produces a **`Timer`** meter: it records both the **count** of executions and the **total/max duration**. Timers expose `_count`, `_sum` (total time) and `_max`. - **`@Counted`** — `io.micrometer.core.annotation.Counted`. Produces a **`Counter`** meter: a monotonically increasing number incremented once per method call. ## Key attributes `@Timed`: - `value` — the metric name. If omitted, the default is **`method.timed`**. - `extraTags` — additional key/value tags as a flat array, e.g. `{"region", "eu"}`. - `description` — human-readable meter description. - `longTask` (boolean, default false) — switch from a `Timer` to a `LongTaskTimer`. - `histogram` (boolean) and `percentiles` (double[]) — distribution statistics (covered in the senior questions). `@Counted`: - `value` — metric name, default **`method.counted`**. - `recordFailuresOnly` (boolean, default false) — only count invocations that threw. - `extraTags`, `description`. ## Automatic tags The aspects add dimensional tags automatically: - `class` — the fully-qualified declaring class. - `method` — the method name. - `exception` — the simple name of the thrown exception, or `none` on success. - (`@Counted` only) `result` — `success` or `failure`. This is what makes them useful: one annotation yields a metric you can slice by class, method, and exception in Prometheus/Grafana. ## How it actually runs Both annotations are inert on their own. At runtime, **Spring AOP** aspects — `TimedAspect` and `CountedAspect` (from `io.micrometer.core.aspect`) — intercept calls to annotated methods, start timing/count before the call, and record after it returns or throws. Because this is proxy-based AOP, the annotations only take effect on **Spring beans** invoked **through their proxy** (external calls), and the aspect beans must exist. In modern Spring Boot (2.5+, with `spring-boot-starter-aop` on the classpath) `MetricsAspectsAutoConfiguration` registers those aspects for you. ## When to use Reach for declarative metrics for coarse, method-level timing/counting of service or repository methods where you want quick observability with minimal code. Prefer **imperative** `Timer`/`Counter` when you need custom/dynamic tag values, to time a sub-section of a method, or to avoid the AOP proxy constraints.
- What tags does @Counted add automatically that @Timed does not?A `result` tag with value `success` or `failure`. Both add `class`, `method`, and `exception`, but only @Counted has the `result` dimension distinguishing normal returns from thrown exceptions.
- If you annotate a method but see no metric published, what is the first thing to check?That the corresponding aspect (TimedAspect/CountedAspect) is registered as a bean and Spring AOP is active, and that the call goes through the Spring proxy (not a self-invocation).
saying these in an interview costs you the question
- Thinking @Timed produces a Counter or @Counted produces a Timer (they are swapped).
- Believing the annotations work anywhere, including on plain non-Spring objects.
- Assuming a metric appears with zero configuration even without the aspect beans.