What is compile-time weaving (CTW) in AspectJ, and how does it differ conceptually from Spring's default AOP?
answer
- ajc weaves into bytecode at build time
- no proxy, no wrapper object
- Spring default = runtime JDK/CGLIB proxy
- aspectjrt at runtime, not aspectjweaver
- advises final/private/self-call
basics
~20 sCompile-time weaving uses the AspectJ compiler (ajc) to merge aspect code directly into class bytecode when you build the project. Spring's default AOP instead wraps beans in runtime proxy objects, weaving nothing at compile time.
solid answer
~40 sIn compile-time weaving the AspectJ compiler (ajc) replaces or supplements javac and writes the advice directly into the .class bytecode at build time. The woven classes already contain the cross-cutting behavior, so no proxy is created and no extra object wraps your bean at runtime. Spring's default AOP is proxy-based: at startup it generates a JDK dynamic proxy or CGLIB subclass around each advised bean, and advice only runs when a call goes through that proxy. CTW moves the cost and the join-point resolution to build time. The practical payoff is that CTW can advise things proxies cannot: final methods, private methods, constructors, and self-invoked calls. The trade-off is a more complex build (ajc, aspectj-maven-plugin/Gradle plugin) and the aspectjrt dependency at runtime.
code
java · 14 lines// A plain aspect, woven into bytecode by ajc at compile time.
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AuditAspect {
// After CTW this advice body is compiled directly into the
// matched methods' bytecode -- no Spring proxy involved.
@Before("execution(* com.katajob.domain..*.*(..))")
public void audit() {
System.out.println("[audit] entering a domain method");
}
}go deeper
Know CTW = ajc weaves at build time; Spring default = runtime proxy. That's the core contrast.
Be able to name the proxy blind spots CTW avoids (final/private/self-call) and the build tooling (ajc, aspectj plugin).
Distinguish CTW from post-compile and load-time weaving and explain the aspectjrt-vs-aspectjweaver dependency split.
Frame the choice as a trade-off between build complexity and join-point reach; know when zero proxy overhead and advising non-Spring objects justify CTW.
**Weaving** is the act of combining ordinary code with *aspects* — modules that capture cross-cutting concerns (logging, security, transactions) expressed as *advice* (code to run) at *join points* (points in execution such as a method call) selected by *pointcuts* (expressions matching join points). **Compile-time weaving (CTW)** does this weaving during the build. You compile with the **AspectJ compiler `ajc`** (from `aspectjtools`, usually driven by the `aspectj-maven-plugin` — now maintained under the `dev.aspectj` groupId — or a Gradle AspectJ plugin). `ajc` reads both your source and your aspects and emits `.class` files in which the advice has already been injected inline at every matched join point. The compiled bytecode is self-sufficient: run it on a plain JVM and the aspect behavior is simply *there*, with no runtime machinery generating wrappers. **Spring's default AOP is proxy-based**, a completely different mechanism. At container startup Spring creates a **proxy** around each advised bean — a **JDK dynamic proxy** if the bean implements an interface, otherwise a **CGLIB** subclass. The proxy intercepts incoming calls, runs the advice, then delegates to the target. Nothing is woven into your actual class files. Because interception depends on going *through* the proxy reference, proxy AOP has well-known blind spots: - **`final` methods/classes** — CGLIB subclasses the target, and you cannot override `final`, so they are silently not advised. - **`private` methods** — never visible to a subclass/interface proxy. - **Self-invocation** — when a method calls `this.other()`, the call skips the proxy, so advice on `other()` does not fire. - **Only Spring-managed beans** — an object you create with `new` is never proxied. CTW has none of these limits because the advice is compiled *into* the method bodies themselves — there is no proxy boundary to bypass. It can advise `final`, `private`, constructors, static initializers, field access, and even objects created with `new` (via `@Configurable`). **The runtime dependency** you still need is `aspectjrt` (the AspectJ runtime), which the woven bytecode calls into. You do NOT need `aspectjweaver` for CTW — that agent is for load-time weaving. **Sibling techniques** to know: - **Post-compile / binary weaving**: `ajc` weaves aspects into *already-compiled* `.class` files or JARs (via `-inpath`), letting you advise third-party bytecode you don't have source for. - **Load-time weaving (LTW)**: weaving is deferred to class-loading time by the `aspectjweaver` java agent, configured via `@EnableLoadTimeWeaving` and `META-INF/aop.xml`. **When to use CTW**: when you must advise join points proxies can't reach (final/private/self-call/domain objects), or want zero per-call proxy overhead, and you can afford the extra build complexity. Otherwise Spring proxy AOP is simpler and needs no special compiler.
- Do you still need the aspectjweaver dependency for compile-time weaving?No. CTW only needs aspectjrt at runtime (and aspectjtools/the plugin at build time). aspectjweaver is the load-time-weaving java agent.