skip to content

What is the default instantiation (lifecycle) model of a Spring @Aspect, and why does it matter for shared state?

level: middleimportance: should knowfreq 45%

answer

  1. default = singleton = one instance
  2. fields shared across all beans + threads
  3. no per-call state in aspect fields
  4. need thread-safety (AtomicInteger)
  5. per-object => perthis/pertarget

basics

~20 s

By default an aspect is a singleton: one shared aspect instance for the whole application context, just like an ordinary singleton bean. So any fields in the aspect are shared across all advised objects and all threads.

solid answer

~40 s

The default AspectJ instantiation model, which Spring uses, is **singleton**: exactly one aspect instance exists and it advises all matched join points. This matches Spring's default singleton bean scope, so an `@Aspect @Component` is a single shared object. The practical consequence: any mutable instance field in the aspect is **shared across every advised bean and every thread**, so it is not safe to hold per-invocation or per-target state there without synchronization. For request/invocation-scoped data, use method-local variables, the `JoinPoint`/`ProceedingJoinPoint` arguments, or thread-safe holders — not aspect fields. If you genuinely need one aspect instance *per advised object*, that is what the non-singleton `perthis`/`pertarget` models provide, but those must be opted into explicitly (and require prototype scope).

code

java · 17 lines
java
@Aspect
@Component
public class CallCountingAspect {

    // SINGLETON aspect: this field is ONE global counter
    // shared by every advised bean and every thread.
    private final java.util.concurrent.atomic.AtomicInteger calls =
            new java.util.concurrent.atomic.AtomicInteger();

    @Before("execution(* com.example.service.*.*(..))")
    public void count() {
        calls.incrementAndGet(); // must be thread-safe: it is shared
    }

    // BAD (for illustration): a plain 'int total' here would race
    // and would NOT be per-target — it is global to the singleton.
}

go deeper

for a junior

Know that an aspect is a singleton by default — one shared instance.

for a middle

Explain the shared-field / thread-safety consequences and where to put per-call state.

for a senior

Relate singleton default to Spring bean scope and articulate when perthis/pertarget is the right escape hatch.

for a principal

Reason about concurrency design of cross-cutting state, ThreadLocal vs per-target aspects, and memory implications of per-object aspects.

**Instantiation model = how many aspect instances exist and when they are created.** AspectJ defines several models; Spring AOP supports **singleton** (the default), plus **perthis** and **pertarget**. **Singleton (default).** One single aspect object is created and used for *all* join points it matches, across the whole `ApplicationContext`. This lines up naturally with Spring's default **singleton bean scope**, so declaring `@Aspect @Component MyAspect` gives you one shared instance. You do not write anything special to get singleton — it is what you get by default. **Why it matters — shared mutable state.** Because there is exactly one instance, its **instance fields are shared globally**. Two independent beans advised by the same aspect, and any number of concurrent threads, all read and write the *same* fields. So: - A field like `private int callCount` becomes a global counter across everything advised — and needs `AtomicInteger`/synchronization to be correct under concurrency. - You must **not** stash per-call or per-target data in aspect fields expecting isolation; it will leak and race. Keep such state in **method-local variables**, or derive it from the `JoinPoint` / `ProceedingJoinPoint` passed into the advice, or use a `ThreadLocal` if it must span the advice body. **Thread-safety.** A singleton aspect is invoked concurrently, so its advice methods must be thread-safe just like any singleton bean's methods. **When per-object state is actually the requirement.** If you truly want the aspect to maintain state tied to *each advised target object* (e.g. one rate-limiter per service instance), the singleton model is wrong. That is exactly the use case for **perthis** (new aspect instance per object executing the matched join point, i.e. per unique `this`) or **pertarget** (per unique target object). Those are non-singleton, created lazily as new matching objects appear, and — in Spring — require the aspect bean to be declared **prototype**-scoped so multiple instances can be created. **Interaction with bean scope.** For the default singleton model, the aspect is a singleton bean; you would not normally change its scope. Do not confuse aspect *instantiation model* (an AspectJ concept about how the aspect itself is instantiated per matched object) with the *scope of the beans being advised*. You can advise prototype/request-scoped beans with a singleton aspect just fine. **Common misconceptions:** thinking each advised bean gets its own aspect copy (it does not, under the default), or that aspect fields are somehow per-invocation. Both are false for the default singleton model.

  • You want a separate counter per advised service instance. Does the default singleton aspect give you that?
    No. The singleton aspect has one shared instance, so one shared field for everything. Per-instance state requires the perthis (per executing object) or pertarget (per target object) instantiation model, declared with prototype scope.
  • Where should you keep data that must live only for the duration of one advised call?
    In method-local variables inside the advice, or passed via ProceedingJoinPoint; if it must cross helper calls within the advice, a ThreadLocal. Never in a shared aspect field.

saying these in an interview costs you the question

  • Claiming each advised bean gets its own aspect instance by default
  • Storing per-invocation state in aspect instance fields
  • Assuming aspect advice is single-threaded / does not need thread-safety
  • Confusing the aspect's instantiation model with the scope of the advised bean

context