skip to content

What do the perthis and pertarget aspect instantiation models do in Spring AOP, and how must the aspect bean be scoped?

level: seniorimportance: should knowfreq 25%

answer

  1. perthis = per unique 'this'/proxy object
  2. pertarget = per unique target object
  3. MUST be prototype-scoped bean
  4. lazy: created on first matched join point
  5. Spring: NO percflow/pertypewithin

basics

~20 s

perthis creates a new aspect instance for each unique object executing a matched join point (each unique 'this'/proxy); pertarget creates one per unique target object. Both are non-singleton, so the aspect bean must be declared with prototype scope so Spring can create multiple instances.

solid answer

~40 s

Spring AOP supports two non-singleton AspectJ models beyond the default singleton: **perthis** and **pertarget**. You declare them in the annotation, e.g. `@Aspect("perthis(com.example.Pointcuts.serviceMethods())")`. With **perthis**, a separate aspect instance is created for each unique object that is `this` (the AOP proxy) at a matched join point; with **pertarget**, one per unique **target** object behind the proxy. In Spring AOP proxying, this practically means one aspect instance per advised bean, letting the aspect hold **per-object state** (counters, rate limiters). Crucially the aspect bean must be **prototype-scoped** so Spring can instantiate it repeatedly. Instances are created **lazily** on first matched join point for a given object. Note Spring does **not** support percflow, percflowbelow, or pertypewithin — only singleton, perthis, and pertarget.

code

java · 21 lines
java
@Aspect("perthis(com.example.SystemArchitecture.businessService())")
@Component
@Scope("prototype")   // REQUIRED: Spring must create one instance per object
public class PerObjectRateLimitAspect {

    // Because a new aspect instance exists per advised object,
    // this field is effectively per-object state (not global).
    private int callsForThisObject = 0;

    @Before("com.example.SystemArchitecture.businessService()")
    public void beforeCall() {
        callsForThisObject++;   // isolated per advised bean
    }
}

// Supporting pointcut holder:
// @Aspect
// class SystemArchitecture {
//   @Pointcut("execution(* com.example.service..*(..))")
//   public void businessService() {}
// }

go deeper

for a junior

Awareness that non-singleton aspect models exist is enough; details not expected.

for a middle

Know perthis/pertarget give per-object state and require prototype scope.

for a senior

Distinguish perthis vs pertarget, explain lazy creation and the prototype requirement, and know the unsupported models.

for a principal

Weigh perthis/pertarget vs a keyed-map singleton for per-object state, reason about memory/lifecycle, and the this-vs-target distinction under proxy semantics.

**Recap of the default.** By default an aspect is a **singleton** — one shared instance for everything. The other models let the aspect keep state tied to individual advised objects. **perthis.** Declared as `@Aspect("perthis(<pointcut>)")`. A **new aspect instance is created for each unique object executing** a join point matched by the pointcut — i.e. per unique `this`. In Spring AOP, `this` at a join point is the **AOP proxy**, so you get one aspect instance per advised (proxied) object. The instance is created **lazily** the first time that particular object hits a matched join point, and it lives as long as that object does. **pertarget.** Declared as `@Aspect("pertarget(<pointcut>)")`. A **new aspect instance per unique target object** — the actual bean instance behind the proxy. In typical Spring AOP setups (singleton target beans, one proxy each) perthis and pertarget behave very similarly; the distinction matters more when `this` (proxy) and target differ, or under AspectJ semantics where `this` can be a caller. **Mandatory prototype scope.** Because these models require Spring to create **multiple** aspect instances, the aspect bean **must be declared with prototype scope** (`@Scope("prototype")` or `scope="prototype"`). A singleton-scoped bean cannot be instantiated per object, so the model would not work. This is the single most important practical rule and a frequent interview point. **Why use them.** When the cross-cutting concern needs **per-object state**: e.g. a per-service-instance call counter, a per-object circuit breaker / rate limiter, or accumulating metrics isolated per target. With a singleton aspect you'd have to build that isolation yourself (e.g. a `Map` keyed by object); perthis/pertarget give it to you structurally. **What Spring does NOT support.** AspectJ additionally defines **percflow**, **percflowbelow**, and **pertypewithin** instantiation models. **Spring AOP supports only singleton, perthis, and pertarget.** Claiming Spring supports percflow/pertypewithin is a red flag. **Pointcut in the model vs advice pointcuts.** The pointcut named inside `perthis(...)`/`pertarget(...)` governs *when a new aspect instance is created* (which objects get their own aspect); your advice methods still have their own pointcuts for *what they intercept*. **Lifecycle / memory considerations.** Since one aspect instance can exist per advised object, and instances are created lazily and retained, be mindful of memory if there are many distinct advised objects. For long-lived singleton service beans this is bounded and fine; for many short-lived proxied objects it can add overhead. **Gotchas.** - Forgetting `@Scope("prototype")` — the model silently won't behave as intended / bean creation fails to multiply. - Expecting perthis to give per-*invocation* isolation — it is per-*object*, not per-call. - Assuming these are common — they are relatively rare; most real aspects are singletons, and per-object state is often handled with a keyed map instead.

  • You declared a perthis aspect but left it singleton-scoped. What is wrong?
    perthis/pertarget need Spring to create multiple aspect instances (one per object), which requires prototype scope. As a singleton the per-object instantiation cannot happen, so the intended per-object behavior is broken.
  • Which AspectJ instantiation models does Spring AOP NOT support?
    percflow, percflowbelow, and pertypewithin. Spring AOP supports only singleton (default), perthis, and pertarget.
  • Is perthis per-invocation or per-object?
    Per-object: one aspect instance per unique object executing the matched join point, created lazily on first match. It is not a fresh aspect per method call.

saying these in an interview costs you the question

  • Saying perthis/pertarget work with a singleton-scoped aspect bean
  • Claiming Spring supports percflow or pertypewithin
  • Describing perthis as per-invocation rather than per-object
  • Confusing perthis (per proxy/this) with pertarget (per target) and treating them as identical in all cases

context