skip to content

Spring AOP vs Full AspectJ

Spring AOP is runtime proxying limited to bean methods with no build step; AspectJ is a language and weaver with far richer join points and lower call overhead. Being able to say when you would switch is the answer interviewers are listening for.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Spring AOP and how does it apply an aspect to a bean at runtime?

level: juniorimportance: must knowfreq 70%

answer

  1. Proxy wraps the bean at runtime
  2. JDK (interface) vs CGLIB (subclass)
  3. Method-execution join points on beans only
  4. No build step, pure Java
  5. @Aspect syntax != AspectJ weaver

basics

~20 s

Spring AOP adds cross-cutting behavior (logging, transactions, security) by wrapping a Spring bean in a proxy. The proxy runs your advice before/after the real method call. It works only on Spring-managed beans and needs no extra build step.

solid answer

~40 s

Spring AOP is a proxy-based aspect framework. At startup Spring wraps each advised bean in a dynamic proxy: a JDK interface proxy if the bean has interfaces, or a CGLIB subclass proxy otherwise (Spring Boot defaults to CGLIB). Callers get the proxy, not the raw object; each call passes through the proxy, which runs the matching advice (an @Around/@Before/@After method on an @Aspect) and then delegates to the target. Because weaving happens by composition at runtime, there is no special compiler or agent — it is pure Java. The trade-off: it only intercepts external calls to public method-execution join points on Spring beans. It cannot advise fields, constructors, static methods, final classes/methods, or plain non-Spring objects, and self-invocation inside the same bean bypasses the proxy.

code

java · 20 lines
java
@Aspect
@Component
public class TimingAspect {

    // Pointcut: every method execution in a *Service bean
    @Around("execution(* com.acme..*Service.*(..))")
    public Object time(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.nanoTime();
        try {
            return pjp.proceed();          // delegate to the real target method
        } finally {
            long micros = (System.nanoTime() - start) / 1_000;
            System.out.println(pjp.getSignature() + " took " + micros + "us");
        }
    }
}

@SpringBootApplication
@EnableAspectJAutoProxy   // implicit in Spring Boot; shown for clarity
public class App { }

go deeper

for a junior

Must know: aspect = reusable cross-cutting code; Spring wraps the bean in a proxy that runs advice around the method.

for a middle

Should articulate JDK vs CGLIB selection and that only bean method executions are join points.

for a senior

Explains the auto-proxy BeanPostProcessor, the annotation-syntax-vs-weaver distinction, and enumerates proxy limitations.

for a principal

Frames proxy weaving as a deliberate zero-friction default and knows exactly the boundary where it stops being sufficient.

## What AOP solves **Aspect-Oriented Programming (AOP)** factors out *cross-cutting concerns* — behavior that would otherwise be scattered across many methods (logging, metrics, `@Transactional`, `@PreAuthorize` security, caching, retry). Instead of copy-pasting that code, you write it once in an **aspect** and declare *where* it applies with a **pointcut**. ### Core vocabulary (all define-once terms) - **Join point**: a point in program execution where an aspect *can* run. In Spring AOP this is always a **method execution** on a Spring bean — nothing else. - **Pointcut**: an expression selecting which join points to advise, e.g. `execution(* com.acme..*Service.*(..))` or `@annotation(org.springframework.transaction.annotation.Transactional)`. - **Advice**: the code that runs at a join point — `@Before`, `@After`, `@AfterReturning`, `@AfterThrowing`, `@Around` (the most powerful; it wraps the call via a `ProceedingJoinPoint` you must `proceed()`). - **Aspect**: a class holding pointcuts + advice, marked `@Aspect`. - **Weaving**: connecting aspects to target code. Spring AOP weaves at **runtime via proxies**. ## How Spring AOP weaves (the mechanism) Spring AOP uses **runtime proxying**. When the container creates a bean that matches an aspect's pointcut, a `BeanPostProcessor` (`AnnotationAwareAspectJAutoProxyCreator`, enabled by `@EnableAspectJAutoProxy` — Spring Boot turns it on automatically) replaces the bean in the context with a **proxy** that has the same type: - **JDK dynamic proxy** — used when the target implements at least one interface. The proxy implements those interfaces and forwards to the target. Callers must reference the interface type. - **CGLIB proxy** — a runtime-generated **subclass** of the target class. Used when there is no interface, or when `proxyTargetClass=true`. **Spring Boot sets `proxyTargetClass=true` by default**, so CGLIB is the common case. Every *external* call goes: `caller -> proxy -> advice chain -> target method`. Because the proxy is created by composition at runtime, **no build step, no javaagent, no special compiler** is needed — it is ordinary Java bytecode generation at startup. ## Note on annotation style vs framework Spring AOP borrows AspectJ's **annotation syntax** (`@Aspect`, `@Pointcut`, `execution(...)`) and the AspectJ pointcut *parser*. This confuses people: using `@Aspect` does **not** mean you are using the AspectJ *weaver*. Spring AOP only understands a **subset** of AspectJ pointcut designators (no `call`, `get`, `set`, `withincode`, etc.) and still weaves with proxies. ## Key limitations (direct consequences of proxying) - Only **public method executions** on **Spring beans** are advisable (CGLIB can technically touch protected, but the model targets public). Private, static, and `final` methods, and `final` classes, cannot be proxied. - **Self-invocation** (`this.other()` inside the same class) skips the proxy — the advice does not run. - Plain objects you `new` yourself are never advised. ## When it is enough For 95% of apps — transactions, security, method logging on service beans — Spring AOP's proxy model is the right, zero-friction choice. You reach for full AspectJ only when you need richer join points or must advise non-Spring objects.

  • Which proxy type does Spring Boot use by default and why does it matter?
    CGLIB, because Boot sets proxyTargetClass=true. It means the target does not need an interface, but the class/method cannot be final, and callers can inject the concrete type.
  • Name two things Spring AOP cannot advise.
    Field access and constructors (no such join points); also private/static/final methods, self-invoked calls, and any object not managed by Spring.

saying these in an interview costs you the question

  • Thinking @Aspect / @EnableAspectJAutoProxy means you are running the AspectJ weaver
  • Believing Spring AOP can advise fields or constructors
  • Claiming it works on any Java object, not just Spring beans
  • Saying it needs a special compiler or javaagent

context

open as a page

Why does an @Transactional (or any advised) method fail to take effect when called from another method in the same class, and how do you fix it?

level: middleimportance: must knowfreq 65%

basics

~20 s

Spring AOP advice runs in the proxy that wraps the bean. An internal call like this.save() goes straight to the real object and never touches the proxy, so the advice (transaction, cache, retry) is skipped. Fix: call through the proxy or use AspectJ.

open as a page

What join points and targets can full AspectJ advise that proxy-based Spring AOP cannot?

level: middleimportance: should knowfreq 45%

basics

~20 s

Spring AOP can only advise public method executions on Spring beans. Full AspectJ can additionally advise constructor calls, field reads/writes, static and private methods, final classes, and plain non-Spring objects — because it rewrites bytecode instead of wrapping a proxy.

open as a page

Compare the weaving models: runtime proxy weaving vs AspectJ compile-time weaving vs AspectJ load-time weaving. How do you enable each?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Spring AOP weaves at runtime by creating a proxy per bean (no build change). AspectJ compile-time weaving uses the ajc compiler to rewrite bytecode when you build. AspectJ load-time weaving rewrites bytecode as classes load, using a javaagent. Later weaving = richer reach but more setup.

open as a page

As an architect, how do you decide whether to stay on Spring AOP or adopt full AspectJ? What are the trade-offs?

level: principalimportance: should knowfreq 30%

basics

~20 s

Default to Spring AOP: it is simple, needs no build or JVM changes, and covers transactions, security, and method logging on beans. Switch to full AspectJ only when you genuinely need what proxies cannot do — field/constructor join points, advising non-Spring or final objects, reliable self-invocation, or lower per-call overhead — and can accept the extra build/agent complexity.

open as a page