๐Ÿงฉ AOP Layer โ€” Aspects, Proxies & Crosscutting Logic Cheatsheet

Essence: The AOP Layer (Aspect-Oriented Programming) gives Spring its superpowers: it can intercept, extend, and wrap method calls at runtime โ€” adding behavior like transactions, security, caching, or logging transparently.


๐Ÿงญ 1. Concept Overview

Object-Oriented Programming (OOP) organizes what things are. Aspect-Oriented Programming (AOP) organizes what they do repeatedly across many places.

Without AOP:

public void transfer() {
    startTransaction();
    try {
        doTransfer();
        commit();
    } catch (Exception e) {
        rollback();
    }
}

With AOP:

@Transactional
public void transfer() {
    doTransfer();
}

Spring inserts the transaction logic around your method automatically.


๐Ÿชž 2. What Is an Aspect?

An Aspect is a class that holds crosscutting logic โ€” code that applies to multiple classes or methods.

Core AOP Terms

Term Meaning Example
Aspect Class containing advice @Aspect class LoggingAspect { ... }
Advice The actual code that runs before/after a method @Before, @After, @Around
Pointcut Rule that selects which methods get intercepted execution(* com.app..*(..))
Join Point A specific point in method execution where advice can run Method call, exception
Proxy Wrapper that intercepts and forwards method calls Generated by Spring

๐Ÿง  3. How AOP Works in Spring

Your Bean (target)
   โ†“
Spring detects AOP annotations
   โ†“
Creates Proxy Bean (wrapper)
   โ†“
Proxy intercepts method call
   โ†“
Applies advice (before/after/around)
   โ†“
Calls target method

Spring uses reflection and dynamic proxies to wrap your bean at runtime โ€” you never call the real object directly.


โš™๏ธ 4. Declaring Aspects

Enable AOP in a configuration class:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}

Define an Aspect:

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.app.service.*.*(..))")
    public void logBefore(JoinPoint jp) {
        System.out.println("Method start: " + jp.getSignature());
    }

    @After("execution(* com.app.service.*.*(..))")
    public void logAfter(JoinPoint jp) {
        System.out.println("Method end: " + jp.getSignature());
    }
}

๐Ÿงฉ 5. Types of Advice

Advice Type Annotation When It Runs Example
Before @Before Before method call Logging, auth checks
After @After After method (success or fail) Cleanup
AfterReturning @AfterReturning Only after success Metrics, caching
AfterThrowing @AfterThrowing On exception Error handling
Around @Around Wraps the method call Transactions, timing

Example โ€” Around Advice

@Aspect
@Component
public class TimingAspect {

    @Around("execution(* com.app..*(..))")
    public Object measure(ProceedingJoinPoint jp) throws Throwable {
        long start = System.nanoTime();
        Object result = jp.proceed();
        System.out.println(jp.getSignature() + " took " + (System.nanoTime() - start) + "ns");
        return result;
    }
}

โš™๏ธ 6. Pointcut Expressions

The execution() designator defines where advice applies.

execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws-pattern?)

Examples:

execution(* com.app.service.*.*(..))      // all methods in package
execution(public * *(..))                 // all public methods
execution(* transfer(..))                 // any method named transfer
execution(* com.app..*(String))           // any method with String arg

Combine rules:

@Before("execution(* com.app.service.*.*(..)) && @annotation(Transactional)")

๐Ÿงฌ 7. Proxy Types โ€” How Spring Intercepts Calls

Spring AOP uses runtime proxies, not compile-time weaving.

Proxy Type Mechanism Applies To Library
JDK Dynamic Proxy Implements interfaces Interface-based beans java.lang.reflect.Proxy
CGLIB Proxy Subclasses the target class Concrete classes (no interfaces) Bytecode generation via CGLIB

Spring decides automatically:

  • If the bean implements an interface โ†’ JDK proxy
  • Otherwise โ†’ CGLIB subclass

๐Ÿ” JDK Proxy Example

MyService proxy = (MyService) Proxy.newProxyInstance(
    clazz.getClassLoader(),
    new Class[]{MyService.class},
    (p, method, args) -> {
        System.out.println("Before call");
        return method.invoke(target, args);
    });

๐Ÿ”ฌ CGLIB Example

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
    System.out.println("Before " + method.getName());
    return proxy.invokeSuper(obj, args);
});
MyService proxy = (MyService) enhancer.create();

๐Ÿงฑ 8. Built-In AOP Features in Spring

Feature Annotation Underlying Mechanism
Transactions @Transactional TransactionInterceptor via AOP
Asynchronous execution @Async AsyncExecutionInterceptor
Caching @Cacheable, @CachePut, @CacheEvict CacheInterceptor
Security @PreAuthorize, @Secured MethodSecurityInterceptor
Retries @Retryable RetryOperationsInterceptor

All of these are implemented as aspects.


๐Ÿงฉ 9. AOP + IoC Integration Flow

1. Context starts
2. Spring scans beans
3. Detects @Aspect classes
4. Builds proxies for target beans
5. Replaces original bean references with proxy
6. Proxies intercept method calls
7. Calls proceed() โ†’ executes target logic

From that moment, every call goes through the proxy pipeline.


โšก 10. Common Pitfalls

Problem Cause Fix
Advice not applied Self-invocation (method calls inside same class) Move method to another bean or use AspectJ compile-time weaving
AOP disabled Missing @EnableAspectJAutoProxy Add in config
No proxy created Final class/method Remove final or use interface
@Transactional not working Calling private/self method Ensure proxy boundary
Order issues Multiple aspects Use @Order annotation

๐Ÿง  11. Debugging Proxies

Check whether a bean is proxied:

System.out.println(AopUtils.isAopProxy(bean));   // true/false
System.out.println(AopUtils.getTargetClass(bean));

Print proxy class:

System.out.println(bean.getClass());  // usually com.sun.proxy.$ProxyXX or CGLIB$$EnhancerBySpringCGLIB

๐Ÿงฎ 12. Custom Aspect Example โ€” Audit Logging

@Aspect
@Component
public class AuditAspect {

    @Around("@annotation(Audit)")
    public Object audit(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("AUDIT โ†’ " + jp.getSignature());
        return jp.proceed();
    }
}

And annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Audit {}

Now @Audit can be added to any method, and the aspect intercepts it.


๐Ÿงฉ 13. Performance Notes

  • Proxy creation happens once at startup; not during runtime.
  • Method interception adds minimal overhead (microseconds).
  • Avoid deep proxy chains (e.g., multiple AOP frameworks stacked).
  • Avoid applying AOP to ultra-hot code paths (like millions of calls/sec).

๐Ÿงญ 14. Quick Reference Summary

Concept Description Spring Mechanism
Aspect Class holding crosscutting logic @Aspect
Advice Code run before/after method @Before, @After, etc.
Pointcut Expression selecting join points execution(...)
Proxy Runtime wrapper intercepting calls JDK / CGLIB
Join Point Intercepted method execution Method entry/exit
ProceedingJoinPoint Around advice controller proceed() executes real method
Aspect order Order of execution @Order(n)
AOP enablement Activate AOP system @EnableAspectJAutoProxy

๐Ÿงฌ 15. Visual Summary

@Target Bean
   โ†“
Detected by @Aspect processor
   โ†“
Proxy Bean Created
   โ†“
Method Call Intercepted
   โ†“
@Before / @Around / @After
   โ†“
Target Method Invoked
   โ†“
Return to Caller


๐Ÿชž Core Takeaway

AOP turns Spring from a factory into an orchestra conductor. It doesnโ€™t just create your objects โ€” it surrounds them with rhythm and timing. Through proxies, it can wrap logic around logic, making crosscutting behavior seamless and centralized. Reflection lets Spring see; IoC lets it build; AOP lets it intervene.