What is weaving, what is the target object, and how does Spring AOP perform weaving compared to AspectJ?
answer
- weaving = link aspect into code so advice runs
- target = real bean; proxy stands in front
- Spring = runtime proxy (JDK iface / CGLIB subclass)
- AspectJ = compile / post-compile / load-time bytecode
- self-invocation bypasses the proxy → advice skipped
basics
~20 sWeaving is linking aspects into your code so advice actually runs. The target object is the real bean being advised. Spring weaves at runtime by wrapping the target in a proxy; AspectJ can weave at compile time or class-load time.
solid answer
~50 s**Weaving** is the process of applying aspects to target code so that advice executes at the matched join points — it's what actually 'connects' the aspect to the program. The **target object** is the original bean whose methods are being advised (the proxy delegates to it). **Spring AOP does runtime weaving via proxies**: when a bean matches a pointcut, Spring creates a proxy — a JDK dynamic proxy if the bean implements an interface, otherwise a CGLIB subclass proxy. Callers get the proxy; each call is intercepted, advice runs, then the proxy delegates to the target. **AspectJ** instead weaves by modifying bytecode: **compile-time** (special compiler), **post-compile/binary** weaving, or **load-time weaving** (a Java agent at class load). Because Spring uses proxies, it only supports method-execution join points and self-invocation bypasses advice; AspectJ can weave field access, constructors, and internal calls.
code
java · 21 lines@Service
public class OrderService {
// Self-invocation pitfall: this.audit() does NOT go through the proxy,
// so @Transactional/@Cacheable/advice on audit() is SKIPPED.
public void placeOrder(Cart c) {
doPlace(c);
this.audit(c); // internal call — proxy bypassed
}
@Transactional
public void audit(Cart c) { /* advice may not fire when called via this. */ }
}
// Fix 1: self-inject the proxy
@Service
public class OrderService2 {
@Autowired private OrderService2 self; // injected = the proxy
public void placeOrder(Cart c) { self.audit(c); } // goes through proxy
@Transactional public void audit(Cart c) { /* advice fires */ }
}go deeper
Should know weaving = connecting aspects to code and that Spring uses proxies at runtime.
Knows target vs proxy and the JDK-vs-CGLIB choice.
Explains the self-invocation gotcha and the three AspectJ weaving times; can pick Spring AOP vs AspectJ.
Reasons about performance, load-time weaving setup, and when the proxy model's limitations justify moving to AspectJ.
## Weaving **Weaving** = the linking step that inserts aspect behavior into the target program so that, at runtime, advice actually fires at the selected join points. Before weaving you have separate business code and separate aspects; after weaving they act as one. There are three moments weaving can happen: 1. **Compile-time weaving** — an AspectJ-aware compiler (`ajc`) weaves aspects while compiling source. The resulting `.class` files already contain the advice calls. 2. **Load-time weaving (LTW)** — a Java agent instruments bytecode *as classes are loaded* by the JVM. Configured via `-javaagent:aspectjweaver.jar` and `aop.xml`; Spring can enable it with `@EnableLoadTimeWeaving`. 3. **Runtime weaving (proxy-based)** — **this is what Spring AOP does.** No bytecode is rewritten; instead a **proxy** object wraps the bean and intercepts calls. ## Target object The **target object** is the actual, unadvised bean instance that holds the real business logic. The proxy is a stand-in placed *in front of* the target: callers hold the proxy, the proxy runs the advice chain, then calls through to the target. `AopUtils`/`AopProxyUtils.ultimateTargetClass()` and `AopContext.currentProxy()` let you reach the real class/proxy when needed. In advice, `JoinPoint.getTarget()` returns the target while `getThis()` returns the proxy. ## How Spring creates the proxy Spring's `AnnotationAwareAspectJAutoProxyCreator` (a `BeanPostProcessor`) inspects beans at startup; if any pointcut matches, it returns a proxy instead of the raw bean: - **JDK dynamic proxy** — used when the target implements at least one interface; the proxy implements those interfaces. Injected dependencies should be typed to the interface. - **CGLIB proxy** — used when there's no interface (or `proxyTargetClass=true`); Spring generates a runtime **subclass** of the target and overrides its methods. Cannot proxy `final` classes/methods. Spring Boot defaults to CGLIB (`proxyTargetClass=true`). ``` caller ──▶ [ Proxy ] ──(advice chain: before → around → ...)──▶ [ Target bean ] ``` ## The famous gotchas of proxy-based weaving - **Self-invocation**: if a bean calls its own method via `this.other()`, the call does **not** go through the proxy, so advice on `other()` is skipped. This bites people with `@Transactional`/`@Cacheable` on internally-called methods. Fixes: inject a self-reference to the proxy, use `AopContext.currentProxy()`, restructure into two beans, or switch to AspectJ LTW. - **Only public method executions** are advised by default (proxy visibility). Private/final methods aren't proxied. - **`final` classes/methods** break CGLIB subclassing. - Proxies add a small per-call indirection cost. ## Spring AOP vs AspectJ — summary | | Spring AOP | AspectJ | |---|---|---| | Weaving | Runtime, proxy-based | Compile-time / post-compile / load-time bytecode | | Join points | Method execution on beans only | Method, constructor, field, init, etc. | | Self-invocation advised? | No | Yes | | Setup | Just Spring, no agent | Compiler or `-javaagent` | | Scope | Spring beans only | Any object, even non-Spring | | Power vs simplicity | Simpler, covers 90% of needs | More powerful, more setup | **When to use which:** Spring AOP for the common cross-cutting cases (transactions, security, logging on service methods) — no extra tooling. Reach for AspectJ (usually via load-time weaving) when you need to advise non-public/internal calls, constructors, field access, or non-Spring objects, or to eliminate self-invocation blind spots.
- Why does a @Transactional method sometimes not run in a transaction when called from within the same class?Self-invocation: the internal this.method() call doesn't pass through the Spring proxy that applies the transaction advice, so the advice is skipped. Fix by calling through the proxy (self-injection, AopContext.currentProxy()), splitting into another bean, or using AspectJ weaving.
- When does Spring use a JDK dynamic proxy vs a CGLIB proxy?JDK dynamic proxy when the target implements an interface (proxy implements that interface); CGLIB (runtime subclass) when there's no interface or when proxyTargetClass=true. Spring Boot defaults to CGLIB. CGLIB can't proxy final classes/methods.
saying these in an interview costs you the question
- Saying Spring AOP rewrites your bytecode (it doesn't — it uses runtime proxies).
- Claiming self-invoked methods still get advice under Spring AOP.
- Thinking JDK proxies can proxy classes without interfaces (that's CGLIB's job).
- Believing AspectJ requires Spring (it's independent and can weave non-Spring objects).