DevNotes
Support
Spring Boot · Chapter 21

Spring AOP

Aspect-oriented programming — cross-cutting concerns, aspects, join points, pointcuts, the five advice types, pointcut expressions, proxies, self-invocation and aspect ordering.

◷ 8 min read§ 21 sections? 10 interview questions{ } 17 code examples

#Introduction

Spring AOP is one of the most important topics for Java developers with 5+ years of experience — almost every major Spring feature uses AOP internally: @Transactional, @Cacheable, @Async, Spring Security, logging, auditing, performance monitoring, exception handling and distributed tracing.

Interviewers commonly ask: What is AOP? Why do we need it? What are cross-cutting concerns? What are an aspect, a join point, a pointcut and advice? How does Spring AOP work internally? JDK dynamic proxy vs CGLIB? Why doesn't AOP work on private methods? Why doesn't self-invocation trigger @Transactional?

#Why Do We Need AOP?

Java
public class UserService {

    public void register() {
        System.out.println("Logging");
        System.out.println("Security Check");
        System.out.println("Transaction Started");
        // business logic
        System.out.println("Transaction Commit");
    }
}

public class OrderService {

    public void placeOrder() {
        System.out.println("Logging");
        System.out.println("Security Check");
        System.out.println("Transaction Started");
        // business logic
        System.out.println("Transaction Commit");
    }
}

Problem: logging, security and transaction code are copied everywhere. This violates the Don't Repeat Yourself (DRY) principle.

#The Solution — Aspect-Oriented Programming

Separate business logic from common concerns:

Business logic
UserServiceOrderServicePaymentService
Cross-cutting concerns
LoggingSecurityTransactionsCachingAuditing
The common logic becomes an Aspect

#What is an Aspect?

An aspect is a class that contains cross-cutting logic:

Java
@Aspect
@Component
public class LoggingAspect {
}

Examples: logging, security, transaction management, auditing, performance monitoring, metrics and exception logging.

#Cross-Cutting Concerns

Business logicCross-cutting concerns
Register userLogging
Create orderAuthentication, authorization
Process paymentTransactions, caching, performance monitoring

Cross-cutting concerns affect multiple modules.

#Core AOP Terminology

TermMeaning
AspectA module of cross-cutting logic
AdviceThe code executed by an aspect
Join pointA method execution that can be advised
PointcutAn expression selecting join points
TargetThe original object
ProxyThe object wrapping the target
WeavingApplying aspects to the target

These definitions are asked in almost every interview.

Join Point

A point during program execution where an aspect can run. In Spring AOP, method execution is the only supported join point type (full AspectJ also supports field access, constructors, etc.). The execution of save() is a join point.

Pointcut

A pointcut decides where advice executes:

Java
@Pointcut("execution(* com.app.service.*.*(..))")
public void serviceLayer() {
}

Meaning: every method inside the service package.

Advice

Advice is the actual code executed by Spring:

Java
@Before("execution(* com.app.service.*.*(..))")
public void log() {
    System.out.println("Method Started");
}

The logging is the advice.

#Types of Advice

AdviceExecutes
@BeforeBefore the method
@AfterAfter the method (success or exception, like finally)
@AfterReturningOnly after successful completion
@AfterThrowingOnly when an exception occurs
@AroundBefore and after — wraps the execution

@Before

Java
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.app.service.*.*(..))")
    public void before() {
        System.out.println("Method Started");
    }
}
Before advice
Business method

@After

Runs after method completion, whether it succeeds or throws:

Java
@After("execution(* com.app.service.*.*(..))")
public void after() {
}

@AfterReturning

Runs only when the method completes successfully:

Java
@AfterReturning(
        pointcut = "execution(* com.app.service.*.*(..))",
        returning = "result")
public void success(Object result) {
    System.out.println(result);
}

@AfterThrowing

Runs only when an exception occurs:

Java
@AfterThrowing(
        pointcut = "execution(* com.app.service.*.*(..))",
        throwing = "ex")
public void error(Exception ex) {
    System.out.println(ex.getMessage());
}

@Around

The most powerful advice:

Java
@Around("execution(* com.app.service.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

    System.out.println("Before");

    Object result = joinPoint.proceed();

    System.out.println("After");
    return result;
}
Before
Business method
After

@Around can skip method execution, execute the method multiple times (rarely appropriate), modify arguments, modify the return value and measure execution time.

ProceedingJoinPoint

An interview favourite. joinPoint.proceed() executes the original business method. Without it, the business method never executes.

#Pointcut Expressions

General syntax:

Text
execution(modifiers? return-type package.class.method(parameters))
PointcutMatches
execution(* *.*(..))Every method
execution(* com.app.service.*.*(..))Every method of classes in the service package
execution(* UserService.save(..))A specific method
execution(String *.*(..))Methods returning String
execution(* *.*(*))Methods with exactly one parameter

(.. in the parameter list means any number of parameters; com.app.service..* would include sub-packages too.)

Named Pointcuts

Java
@Pointcut("execution(* com.app.service.*.*(..))")
public void services() {
}

@Before("services()")

Improves readability and maintainability.

#Internal Working of Spring AOP

For @Transactional public void save(), Spring does not modify your class. Instead:

UserService
Proxy created
Proxy executes transaction logic
Original method

The Proxy Pattern

Without AOP
Client
UserService
With AOP
Client
Proxy
Logging → transaction → security
UserService

The proxy intercepts the call.

JDK Dynamic Proxy

Used when the target implements at least one interface:

Java
public interface PaymentService {
}

public class PaymentServiceImpl implements PaymentService {
}

The proxy implements the same interfaces and can't proxy classes directly.

CGLIB Proxy

Used when no interface-based proxy is chosen:

Java
@Service
public class UserService {
}

Spring creates a subclass at runtime (UserService → generated subclass → proxy). It proxies concrete classes, but can't override final methods or subclass final classes.

Proxy Selection

Does the target implement an interface?
JDK proxy
CGLIB proxy

#Why Private Methods Don't Work

Java
@Transactional
private void save() {
}

The proxy cannot intercept a private method — private methods aren't overridable (CGLIB) and aren't part of any interface (JDK proxy), so proxy-based AOP can't advise them.

#Why Final Methods Don't Work (CGLIB)

Java
final void save() {
}

CGLIB works by overriding methods. Final methods can't be overridden → no AOP.

#The Self-Invocation Problem

Interview favourite.

Java
@Service
public class UserService {

    public void register() {
        save();
    }

    @Transactional
    public void save() {
    }
}
register()
this.save()
Direct call
Proxy bypassed
No transaction

Why? Because the call stays inside the same object and never passes through the proxy. Solutions:

  • Move the transactional method to another bean
  • Call through the proxy (advanced usage, e.g. self-injection)
  • Refactor responsibilities

#Order of Multiple Aspects

Java
@Order(1)
class SecurityAspect {
}

@Order(2)
class LoggingAspect {
}

Lower order value = higher priority — it runs first on the way in and last on the way out.

#Enabling AOP

Java
@EnableAspectJAutoProxy

In Spring Boot, AOP is enabled automatically when the AOP starter (spring-boot-starter-aop) is on the classpath; @EnableAspectJAutoProxy is still available for explicit configuration.

#Internal Spring Components

ApplicationContext
BeanPostProcessor
AnnotationAwareAspectJAutoProxyCreator
Create proxy
Client receives proxy

#Internal Execution Flow

For advice in the same aspect (Spring 5.2.7+):

Client → proxy
@Around (before proceed)
@Before
Business method
@AfterReturning — or @AfterThrowing if an exception occurred
@After
@Around (after proceed)

#Common Mistakes

  • Forgetting @Aspect — @Component class Logging {} alone is just a normal bean.
  • Forgetting proceed() — an @Around method that returns null without calling p.proceed() means the business method never executes.
  • Applying AOP to private methods — won't work; use public (or otherwise proxy-interceptable) methods.
  • Self-invocation — this.method() bypasses the proxy.
  • Heavy business logic inside an aspect — keep aspects focused on cross-cutting concerns.

#Enterprise Architecture

HTTP request
Controller
Proxy
Logging aspect
Security aspect
Transaction aspect
Service
Repository
Database

#Real-World Uses of Spring AOP

FeatureUses AOP?
@Transactional✓
@Async✓
@Cacheable✓
Method security (@PreAuthorize)✓
Logging✓
Metrics✓
Auditing✓

#Interview Questions

Q1What is AOP?

Aspect-Oriented Programming is a paradigm that separates cross-cutting concerns (such as logging and transactions) from business logic.

Q2What is an Aspect?

A class containing cross-cutting logic.

Q3What is a Join Point?

In Spring AOP, a method execution that can be intercepted by an aspect.

Q4What is a Pointcut?

An expression that selects which join points receive advice.

Q5What is Advice?

The action executed by an aspect at a selected join point.

Q6Difference between @Before and @Around?
@Before@Around
Runs before the methodWraps the method execution
Can't control executionControls whether and when the method executes
SimplerMost powerful advice type
Q7Difference between JDK Dynamic Proxy and CGLIB?
JDK proxyCGLIB
Proxies interfacesProxies classes
Requires an interfaceWorks with concrete classes
Uses java.lang.reflect.ProxyGenerates subclasses
Can't proxy classes directlyCan't proxy final classes or final methods
Q8Why doesn't AOP work on private methods?

Because proxy-based AOP can't intercept private methods — they aren't overridable or callable through the proxy.

Q9Why does self-invocation break @Transactional?

Because this.method() calls the target object directly and bypasses the Spring proxy.

Q10Which class creates AOP proxies?

AnnotationAwareAspectJAutoProxyCreator — the key Spring infrastructure component that creates AspectJ-style proxies.

#Key Takeaways

  • Spring AOP separates cross-cutting concerns from business logic.
  • Core concepts: aspect, advice, join point, pointcut, target, proxy and weaving.
  • @Around is the most powerful advice — it controls execution via ProceedingJoinPoint.
  • Spring AOP is proxy-based, using JDK dynamic proxies or CGLIB.
  • Private methods, final methods (CGLIB) and self-invocation are common proxy limitations.
  • Transactions, caching, async execution and security are implemented with AOP.