skip to content

What is the difference between the this() and target() pointcut designators?

level: middleimportance: must knowfreq 60%

answer

  1. this = proxy object; target = real object
  2. both dynamic, both can bind
  3. JDK proxy: this(ConcreteClass) fails
  4. target() = safe for concrete class
  5. single type only, no wildcards

basics

~20 s

this() tests the AOP proxy object's type; target() tests the underlying real object's type. Both can also bind that object into the advice. They differ when the proxy's type is not the same as the target's type.

solid answer

~50 s

Both this() and target() are dynamic pointcut designators that match on the runtime type of an object, and both can bind that object as an advice parameter. The difference is *which* object: this(SomeType) matches when the **proxy** (the reference the caller holds and calls through) is an instance of SomeType; target(SomeType) matches when the **target** (the actual bean instance being wrapped) is an instance of SomeType. For most cases they select the same join points, because the proxy usually implements/extends the same types as the target. They diverge with **JDK dynamic proxies**: a JDK proxy implements only the target's interfaces, so it is NOT an instance of the concrete target class — this(ConcreteClass) fails to match while target(ConcreteClass) still matches. Use target() to match on a concrete class; use this() when you must reference the proxy itself.

code

java · 22 lines
java
public interface OrderService { void place(); }

@Service
public class OrderServiceImpl implements OrderService {
    public void place() { /* ... */ }
}

@Aspect @Component
class MatchAspect {
    // Fires under BOTH JDK and CGLIB proxies (interface is on the proxy).
    @Before("this(com.example.OrderService)") void a() {}

    // Under a JDK dynamic proxy this NEVER fires (proxy is not an OrderServiceImpl).
    @Before("this(com.example.OrderServiceImpl)") void b() {}

    // Fires under both: the target really is an OrderServiceImpl.
    @Before("target(com.example.OrderServiceImpl)") void c() {}

    // Binding the target object for use in the advice body.
    @Before("target(svc)")
    void d(OrderService svc) { System.out.println("target = " + svc); }
}

go deeper

for a junior

Know the one-liner: this()=proxy, target()=real object, both check runtime type.

for a middle

Explain the JDK-proxy divergence and that target() is the safe choice for concrete classes; know both can bind.

for a senior

Reason about binding semantics (proxy vs raw object, self-invocation), and dynamic-vs-static cost.

for a principal

Advise teams on proxy strategy (interface-first + target(), or proxyTargetClass) and codify marker-interface pointcuts across a codebase.

## The two objects in proxy-based AOP Spring AOP is **proxy-based**. When a bean is advised, Spring hands callers a **proxy** object. Inside that proxy sits the **target** — the real bean instance whose method actually runs. So at every advised call there are two objects: - **proxy** = the object the caller holds and invokes (`this` from the caller's perspective). - **target** = the underlying real object (`this` from inside the method body). `this()` and `target()` are the two PCDs that let you match/bind on these: - `this(Type)` → matches when the **proxy** is an `instanceof Type`. - `target(Type)` → matches when the **target** is an `instanceof Type`. Both are **dynamic** PCDs (in general a runtime `instanceof` test), and both support **binding**: naming a variable instead of a type captures the object for use in the advice body. ## Why they usually behave the same A proxy is built to be substitutable for the target, so it normally implements/extends the same set of types. Hence `this(OrderService)` and `target(OrderService)` typically select the same join points. The divergence is entirely about **how the proxy was created**. ## Where they diverge: JDK vs CGLIB proxies Spring creates one of two proxy kinds: 1. **JDK dynamic proxy** (default when the bean has at least one interface, unless CGLIB is forced): the proxy is a runtime class that **implements the target's interfaces** but is a subclass of `java.lang.reflect.Proxy` — it is **NOT** a subclass of the concrete target class. 2. **CGLIB proxy** (used when there is no interface, or `proxyTargetClass=true`): the proxy is a **runtime subclass of the concrete target class**, so it IS an `instanceof` that class. Consequences, assuming `OrderServiceImpl implements OrderService`: | PCD | JDK proxy | CGLIB proxy | |-----|-----------|-------------| | `this(OrderService)` (interface) | matches | matches | | `this(OrderServiceImpl)` (class) | **no match** — proxy isn't an instance of the impl class | matches | | `target(OrderService)` | matches | matches | | `target(OrderServiceImpl)` | matches — target IS the impl | matches | So the rule of thumb: **to match on a concrete class, use `target()`** (or force CGLIB). `this()` on a concrete class silently fails under JDK proxying — a classic 'my aspect isn't firing' bug. ## Binding form ```java @Before("target(orderService)") public void audit(OrderService orderService) { ... } // binds the target @Before("this(proxyRef)") public void audit(OrderService proxyRef) { ... } // binds the proxy ``` The **parameter type** in the advice method determines the type used in the `instanceof` test (the pointcut names a *variable*, and its declared type in the method signature supplies the type). Binding `this()` gives you a handle you could re-invoke through (going through advice again); binding `target()` gives the raw object (calls on it bypass the proxy — no self-invocation advice). ## Gotchas - `this()`/`target()` take a **single type name or a bound variable** — no wildcards/package patterns (unlike `within()`). `target(com.example..*)` is invalid. - They are **dynamic** — potentially a per-call runtime check — so prefer static PCDs (`within`, `execution`) when a static type match suffices; combine, e.g. `execution(* *(..)) && target(com.example.Auditable)`. - Matching an **interface implemented only by the target but not exposed on the proxy** is not possible with `this()` under JDK proxies — again use `target()`. ## When to use - Match/bind by a **marker interface** the bean implements (e.g. `target(com.example.Auditable)`) → advise any bean of that capability. - Use `target()` for concrete-class matching and to get the real object; use `this()` only when you specifically need the proxy reference.

  • You wrote this(OrderServiceImpl) and the advice never runs. What is the likely cause and fix?
    The bean is JDK-dynamic-proxied because it implements an interface, so the proxy is not an instance of the concrete OrderServiceImpl. Fix: match on the interface, use target(OrderServiceImpl), or force CGLIB with proxyTargetClass=true.
  • Do this() and target() incur a runtime cost per invocation?
    They are dynamic PCDs and may require a runtime instanceof check, though Spring can often resolve the type statically at proxy creation. Still, prefer static PCDs like within()/execution() when they suffice and AND the dynamic one on top.

context