What is Load-Time Weaving (LTW) in Spring AOP, and how does it differ from Spring's default proxy-based AOP?
answer
- weaving = merge advice into target
- proxy = wrapper object; LTW = real bytecode
- LTW needs a Java agent + aop.xml
- LTW advises non-beans + self-invocation
- proxies are the simpler default
basics
~10 sLoad-Time Weaving inserts aspect code into class bytecode as the JVM loads each class, using a Java agent. Spring's default AOP instead wraps beans in runtime proxy objects and only advises Spring-managed beans.
solid answer
~40 sWeaving means merging aspect code (advice) into the classes it applies to. Spring's default is proxy-based (dynamic) weaving: at container startup Spring wraps advised beans in a JDK or CGLIB proxy, so advice only runs when calls go through that proxy — limited to Spring beans and external method calls. Load-Time Weaving (LTW) instead modifies the actual bytecode of a class the moment the classloader loads it, via an AspectJ ClassFileTransformer installed by a Java agent. Because the real class bytes change, LTW can advise any class (not just Spring beans), including internal/self-invocation calls, private methods, and objects created with new. You enable it with @EnableLoadTimeWeaving plus a META-INF/aop.xml listing the aspects. It is heavier to set up and needs an agent, so most apps stay with proxies.
code
java · 9 lines// Enable LTW in a Spring configuration class
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
// Also required on the classpath:
// META-INF/aop.xml (lists the aspects to weave)
// And on the JVM command line, an agent, e.g.:
// -javaagent:/path/to/spring-instrument-<ver>.jar
}go deeper
Know that weaving = merging aspect code into targets, and that LTW does it at class-load time via bytecode while default Spring AOP uses proxies.
Be able to name the three enabling pieces (@EnableLoadTimeWeaving, aop.xml, the agent) and the proxy limitations LTW overcomes.
Explain the ClassFileTransformer/instrumentation mechanism and articulate a clear when-to-use vs proxies trade-off.
Weigh operational cost (agent, startup, classloader coupling) and steer teams away from LTW unless a proxy limitation is truly blocking.
## What 'weaving' means An **aspect** is a module of cross-cutting behavior (logging, transactions, security). Its **advice** (the code to run) must eventually be combined with the target classes it applies to. That combination step is called **weaving**. Weaving can happen at three times: - **Compile-time weaving** — the AspectJ compiler (`ajc`) merges aspects into `.class` files at build time. - **Load-Time Weaving (LTW)** — aspects are merged into a class's bytecode *as the JVM loads that class*, before it is defined. - **Runtime proxy weaving** — Spring's default: no bytecode is changed; instead a wrapper object (proxy) intercepts calls. ## Spring's default: proxy-based AOP By default (`@EnableAspectJAutoProxy`, on by Spring Boot) Spring creates a **proxy** around each advised bean at container startup — a **JDK dynamic proxy** if the bean implements an interface, otherwise a **CGLIB** subclass. Advice runs only when a caller invokes a method **through that proxy reference**. Consequences/limits: - Only **Spring-managed beans** can be advised (Spring must own the instance to wrap it). - **Self-invocation is not advised**: when a method inside the bean calls `this.other()`, the call bypasses the proxy, so `other()`'s advice does not fire. - **private / final / static** methods can't be advised (JDK proxies need interface methods; CGLIB subclasses can't override final/private). ## Load-Time Weaving LTW takes a completely different route: it changes the **actual bytecode** of the class. A **`ClassFileTransformer`** (a JVM hook from `java.lang.instrument`) is registered so that every time a classloader is about to define a class, the AspectJ weaver inspects the bytes, and if an aspect's pointcut matches, it **injects the advice directly into the method bodies**. The loaded class *is* the woven class — there is no separate proxy object. Because the real bytes change, LTW removes the proxy limitations: it can advise **any class** (not only Spring beans), **self-invocations**, `new`-created objects, and — with AspectJ — even non-public methods, depending on the pointcut. This is why frameworks historically used LTW for things like `@Configurable` domain-object injection and full AspectJ transaction weaving. ## How you turn it on (Spring) 1. Annotate a `@Configuration` class with **`@EnableLoadTimeWeaving`** (or add `<context:load-time-weaver/>` in XML). 2. Provide a **`META-INF/aop.xml`** file listing which aspects to weave and which packages to include (this is the AspectJ weaver's config, not a Spring file). 3. Supply an **agent** so the JVM can transform classes: `-javaagent:spring-instrument.jar` or `-javaagent:aspectjweaver.jar` on the launch command (some servers register a weaver automatically). ## When to use it Reach for LTW only when proxies genuinely can't do the job — e.g. you must advise self-invocations, non-Spring objects, or domain objects created with `new`. Otherwise proxies are simpler, need no agent, and are the recommended default. LTW adds startup cost, an agent dependency, and classloader complexity.
- Why can proxy-based AOP not advise a self-invocation (this.method()) but LTW can?A proxy only intercepts calls that pass through the proxy reference. An internal this.method() call uses the raw target instance directly, bypassing the proxy. LTW rewrites the actual method bytecode, so the advice is embedded regardless of how the method is reached.