AspectJ distinguishes execution() from call() and offers get()/set()/initialization(). Which of these does Spring AOP actually implement, and why?
answer
- Spring = execution only
- call/get/set/initialization → AspectJ weaving
- Unsupported → UnsupportedPointcutPrimitiveException
- within/this/target/args/@annotation OK
- this=proxy, target=bean
basics
~10 sSpring AOP implements only method execution. It does not support call, get/set (fields), initialization (constructors), staticinitialization, or handler, because a runtime proxy can only intercept a method being executed on the wrapped bean.
solid answer
~40 sSpring AOP reuses AspectJ's pointcut *syntax* but is a runtime proxy, so it maps only to AspectJ's method **`execution`** join point. `call()` matches the caller's call *site* — a proxy can't see who calls it, only that its own method runs — so Spring omits it (in practice `execution` is what you want under Spring anyway). `get()`/`set()` (field access), `initialization()`/`preinitialization()` (constructors), `staticinitialization`, and `handler` (exception handlers) all need bytecode-level weaving and have no proxy hook, so Spring rejects them — using them yields an `UnsupportedPointcutPrimitiveException` at startup. Supporting designators that *do* work in Spring (as matchers narrowing method execution) include `within`, `this`, `target`, `args`, `@annotation`, `@within`, `@target`, `@args`, and `bean`. For any unsupported join point you need full AspectJ (CTW or LTW).
code
java · 19 lines@Aspect
@Component
public class PcdDemoAspect {
// SUPPORTED: execution + refining designators
@Around("execution(* com.example..*Service.*(..)) && @annotation(org.springframework.transaction.annotation.Transactional)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
// SUPPORTED: bean() and target() narrow method-execution join points
@Before("bean(orderService) && target(com.example.OrderService)")
public void beforeOrderBean() { }
// UNSUPPORTED in Spring AOP -> UnsupportedPointcutPrimitiveException at startup:
// @Before("call(* com.example..*.*(..))") // call site
// @After("get(* com.example..*)") // field read
// @After("initialization(com.example..*.new(..))") // constructor
}go deeper
Just knowing 'Spring = method execution only' is enough at this level.
Should know that field/constructor pointcuts aren't supported.
Enumerate supported vs unsupported PCDs and know the startup exception for unsupported ones.
Reason about this()/target() proxy semantics and articulate why the runtime-proxy model precludes weaving-only join points.
## AspectJ's pointcut designators (PCDs) AspectJ defines many **kinds** of join points, each selected by a pointcut designator: - **`execution(...)`** — the **execution** of a method/constructor body. Matched *inside* the callee. - **`call(...)`** — the **call site** of a method/constructor. Matched *inside the caller*, before dispatch. - **`get(...)` / `set(...)`** — reading / writing a **field**. - **`initialization(...)` / `preinitialization(...)`** — **constructor** execution join points. - **`staticinitialization(...)`** — a class's **static initializer** running. - **`handler(...)`** — an **exception handler** (catch block) executing. - **`adviceexecution()`** — execution of advice itself. ## What Spring AOP implements Spring AOP is **proxy-based**, purely a runtime construct. The proxy can observe exactly one thing: *its own method is being executed on the target bean*. Therefore Spring maps only to AspectJ's **`execution`** join point. Everything requiring visibility into other program points needs **bytecode weaving**, which Spring's proxies don't do: - **`call`** — would require instrumenting the *caller's* code. A proxy can't see the call site. (Note: under Spring, `execution` already covers the practical need, since interception is on the callee anyway.) - **`get`/`set`** — no field-access hook in a proxy. - **`initialization`/`preinitialization`** — the proxy is created *after* the target is constructed, so it can't wrap construction. - **`staticinitialization`, `handler`** — no proxy hook at all. If you write a Spring `@Aspect` pointcut using an unsupported primitive (e.g. `@Before("set(* *..*)")`), Spring's pointcut parser throws `org.springframework.aop.framework.AopConfigException` wrapping an **`UnsupportedPointcutPrimitiveException`** at context startup. ## Supported designators that *refine* method execution These work in Spring AOP because they merely **narrow** which method-execution join points match — they don't introduce new join-point kinds: - **`within(pkg..*)`** — join points within given types. - **`this(Type)`** — proxy is an instance of Type (matches the *proxy*). - **`target(Type)`** — target object is an instance of Type. - **`args(...)`** — argument types/values. - **`@annotation(Ann)`** — method carries annotation `Ann`. - **`@within` / `@target`** — the declaring/target *class* carries an annotation. - **`@args`** — argument runtime types carry an annotation. - **`bean(name)`** — Spring-specific: match by bean name/pattern. ## Subtlety: `this` vs `target` under proxies Because Spring interposes a proxy, `this()` refers to the **proxy object** and `target()` to the **underlying bean**. With a JDK proxy the proxy is *not* an instance of the concrete class (only its interfaces), which affects `this()` matching — a real senior-level nuance. ## Why this matters (the granularity gap) Proxy AOP's method-execution-only model is deliberately narrow: it keeps AOP a lightweight, no-build-step runtime feature that cleanly covers the dominant needs (transactions, security, caching, logging on inter-bean method calls). When you need finer granularity — trace every field mutation for auditing, intercept domain-object constructors, weave into non-Spring classes — you graduate to **full AspectJ**: compile-time weaving (`ajc`) or load-time weaving (`spring-instrument` agent + `@EnableLoadTimeWeaving`). AspectJ rewrites bytecode, unlocking every PCD above. ## When to use which - Default to Spring AOP; it's enough for annotation-driven concerns on bean method boundaries. - Move to AspectJ only for the non-method join points or to reach objects Spring doesn't manage — accepting the extra build/agent complexity.
- Under Spring AOP, what's the practical difference between execution() and call()?execution() matches inside the callee (the method being run); call() matches at the caller's call site. Spring only supports execution() because the proxy intercepts the callee. For Spring's proxy model, execution() is the natural and only choice; call() would need the caller's bytecode woven.
- What happens at startup if you use set() in a Spring @Aspect pointcut?Spring's pointcut parser can't handle it and throws an AopConfigException wrapping UnsupportedPointcutPrimitiveException, failing the application context startup.
saying these in an interview costs you the question
- Claiming Spring supports call() as an alias of execution()
- Saying get()/set() work if you enable @EnableAspectJAutoProxy
- Confusing this() and target() (thinking this() is the raw bean)