Spring Boot Aspect-Oriented Programming (AOP)

Complete beginner-friendly chapter — auto-configuration, proxies, AspectJ, advice, pointcuts and practical usage
Source basis: Current Spring Boot 4.1.1 AOP documentation. The official Boot page is short, so the AOP terminology and examples below also use the linked Spring Framework AOP reference to explain the concepts needed to understand Boot's settings.

1. The Big Idea

AOP means Aspect-Oriented Programming. It is useful when the same behavior must apply across many classes or methods, such as logging, auditing, timing, security-related checks or transaction infrastructure.

Many business methods
        ↓
same cross-cutting concern
        ↓
        AOP
        ↓
one reusable aspect
Simple idea: AOP separates a cross-cutting concern from the main business logic and applies it to selected methods.

2. OOP vs AOP

OOPAOP
Main unit is class/object.Main unit is aspect.
Focuses on business objects and responsibilities.Focuses on behavior cutting across multiple objects.
Example: OrderService.Example: timing every service method.

3. Spring Boot AOP Defaults

FeatureSpring Boot behavior
AOP auto-configurationProvided automatically.
Default proxyCGLIB.
JDK proxySet spring.aop.proxy-target-class=false.
AspectJ on classpathAspectJ auto-proxy support is automatically enabled.
@EnableAspectJAutoProxyNot required when Boot's AspectJ auto-configuration applies.
The official Spring Boot page explicitly states that Boot defaults to CGLIB and that setting spring.aop.proxy-target-class to false selects JDK proxies.

4. Cross-Cutting Concerns

A cross-cutting concern affects multiple unrelated parts of an application.

LoggingAuditingTransactionsPerformance timingSome security checks

Without AOP, repeated infrastructure code can be placed inside every method. With AOP, the behavior can be defined once and applied through a pointcut.

5. Important AOP Terminology

TermSimple meaning
AspectModule containing a cross-cutting concern.
Join pointA point during execution where advice can apply. In Spring AOP, this represents method execution.
AdviceAction performed at a matched join point.
PointcutRule that selects matching join points.
Target objectObject being advised.
AOP proxyProxy through which Spring applies advice.
WeavingConnecting aspects with application behavior; Spring AOP uses runtime proxies.
Memory: Aspect = WHAT concern?   Pointcut = WHERE?   Advice = WHAT action?   Proxy = HOW Spring intercepts.

6. How Spring AOP Works

Caller
  ↓
Spring AOP proxy
  ↓
Advice
  ↓
Target method
  ↓
Advice / return
  ↓
Caller

Spring AOP is proxy-based. The proxy intercepts eligible calls and applies the configured advice around the target method.

7. CGLIB Proxies

Spring Boot's default AOP proxy strategy is CGLIB. This is class-based proxying and is useful when the target is a concrete class.

public class OrderService {
    public void createOrder() {
        // business logic
    }
}
Interview: Spring Boot AOP default = CGLIB.

8. JDK Dynamic Proxies

To use JDK dynamic proxies instead:

spring.aop.proxy-target-class=false
ProxyBoot settingSimple idea
CGLIBDefaultClass-based proxying.
JDK dynamic proxyfalseInterface-based proxying.

9. AspectJ and Spring Boot

If AspectJ is on the classpath, Spring Boot's auto-configuration automatically enables AspectJ auto-proxy support. Therefore, you do not need to manually add:

@EnableAspectJAutoProxy
Important: Do not add @EnableAspectJAutoProxy just because you are using Spring Boot. Boot can configure it automatically when AspectJ is present.

10. Creating a Basic Aspect

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service..*(..))")
    public void beforeServiceMethod() {
        System.out.println("Service method called");
    }
}
CodeMeaning
@AspectMarks the class as an aspect.
@ComponentRegisters it as a Spring bean.
@BeforeRuns before matching method execution.
execution(...)Pointcut selecting method executions.

11. Advice Types

AdviceWhen it runsTypical use
@BeforeBefore matched method.Validation, logging.
@AfterReturningAfter normal completion.Successful-result handling.
@AfterThrowingWhen an exception is thrown.Error auditing.
@AfterAfter completion, success or failure.Cleanup.
@AroundAround execution.Timing, wrapping, conditional execution.
Best practice: Use the least powerful advice that solves the problem. Do not use @Around when @Before or @AfterReturning is enough.

12. Before Advice

@Before("execution(* com.example.service..*(..))")
public void before() {
    System.out.println("Before service method");
}

Flow:

@Before → target method → return

13. After Returning Advice

@AfterReturning(
    pointcut = "execution(* com.example.service..*(..))",
    returning = "result"
)
public void afterReturning(Object result) {
    System.out.println("Result = " + result);
}

This advice runs only after normal completion.

14. After Throwing Advice

@AfterThrowing(
    pointcut = "execution(* com.example.service..*(..))",
    throwing = "ex"
)
public void afterThrowing(Exception ex) {
    System.out.println("Failure: " + ex.getMessage());
}

This advice runs when a matched method exits by throwing an exception.

15. After Advice

@After("execution(* com.example.service..*(..))")
public void after() {
    System.out.println("Method finished");
}

Think of @After as finally-like behavior: it runs regardless of normal or exceptional completion.

16. Around Advice

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

    long start = System.currentTimeMillis();

    Object result = joinPoint.proceed();

    long time = System.currentTimeMillis() - start;

    System.out.println("Execution time: " + time + " ms");

    return result;
}
@Around starts
     ↓
before logic
     ↓
joinPoint.proceed()
     ↓
target method
     ↓
after logic
     ↓
return result
Critical: In normal around advice, proceed() allows the underlying method to run. Forgetting it can prevent the target method from executing.

17. Pointcuts

A pointcut tells Spring which method executions should receive advice.

execution(* com.example.service..*(..))

Conceptually:

execution(
  any return type
  com.example.service package/subpackages
  any method
  any arguments
)

Examples:

execution(* com.example.service.OrderService.createOrder(..))

execution(* com.example.service..*(..))

execution(public * com.example.service..*(..))
Memory: Pointcut = WHERE the advice should run.

18. Aspect = Pointcut + Advice

@Before("execution(* com.example.service..*(..))")
public void log() {
    System.out.println("Service called");
}

The pointcut answers where. The advice method answers what.

19. Practical Example: Performance Timing

@Aspect
@Component
public class PerformanceAspect {

    @Around("execution(* com.example.service..*(..))")
    public Object measure(ProceedingJoinPoint pjp) throws Throwable {

        long start = System.nanoTime();
        Object result = pjp.proceed();
        long duration = System.nanoTime() - start;

        System.out.println(
            pjp.getSignature().getName()
            + " took " + duration + " ns"
        );

        return result;
    }
}

One aspect can measure many service methods without putting timing code into each service.

20. Practical Example: Auditing

@AfterReturning(
    pointcut = "execution(* com.example.service.OrderService.create*(..))"
)
public void audit() {
    System.out.println("Order operation completed");
}

This illustrates a cross-cutting audit concern. In production, use an appropriate audit/logging infrastructure rather than relying only on System.out.

21. Practical Example: Security-Related Check

@Before("execution(* com.example.admin..*(..))")
public void checkAccess() {
    // check current user's permission
}

This demonstrates the AOP idea. For real authentication and authorization, Spring Security is generally the more appropriate dedicated solution.

22. Spring AOP vs Full AspectJ

Spring AOPAspectJ
Proxy-based.Provides broader weaving capabilities.
Commonly targets Spring-managed method execution.Can operate beyond the proxy-based model.
Simple Spring integration.More powerful and more complex.
The Spring Boot page focuses on Boot auto-configuration; the linked Spring Framework reference provides the broader AOP programming model.

23. Self-Invocation — Important Limitation

Because Spring AOP is proxy-based, an internal call from one method to another method on the same target object can bypass the proxy.

class OrderService {
    public void methodA() {
        methodB(); // direct internal call
    }

    public void methodB() {
        // advice may not run here
    }
}
external caller
     ↓
Spring proxy
     ↓
methodA()
     ↓
this.methodB()
     ↓
target object directly
Interview point: If advice is not firing for an internally called method, self-invocation is an important thing to check.

24. AOP and Transactions

Transaction management is a classic cross-cutting concern.

@Transactional
public void placeOrder() {
    // database operations
}
caller
  ↓
proxy
  ↓
begin transaction
  ↓
placeOrder()
  ↓
commit / rollback

This is the type of infrastructure behavior AOP helps apply declaratively around business operations.

25. Good AOP Use Cases

UseWhy AOP fits
Execution timingSame behavior across many methods.
Audit loggingCross-cutting and repetitive.
Transaction boundariesInfrastructure around business operations.
Consistent diagnosticsCentralized behavior.

26. When Not to Use AOP

  • When behavior belongs to one business method.
  • When normal composition is simpler.
  • When AOP makes execution flow difficult to understand.
  • When another Spring feature already solves the problem better.
  • When a pointcut would unintentionally affect too many methods.

27. Spring Boot Configuration

spring.aop.proxy-target-class=true

This represents the default CGLIB/class-based strategy.

To use JDK proxies:

spring.aop.proxy-target-class=false
ValueMeaning
trueCGLIB/class-based proxying.
falseJDK dynamic proxies.

28. Common Mistakes

  1. Thinking AOP intercepts everything. A pointcut must match.
  2. Forgetting Spring bean registration. A typical aspect needs component registration.
  3. Using overly broad pointcuts. They can affect unrelated methods.
  4. Using @Around everywhere. Prefer simpler advice when possible.
  5. Forgetting proceed(). The target may not execute.
  6. Expecting self-invocation to trigger advice. Internal calls can bypass the proxy.
  7. Changing proxy strategy without a reason. Boot's default is usually sufficient.
  8. Adding @EnableAspectJAutoProxy unnecessarily. Boot can auto-configure it when AspectJ is present.

29. Best Practices

  • Keep pointcuts narrow and intentional.
  • Use meaningful aspect names.
  • Prefer the simplest advice type that works.
  • Keep business logic separate from infrastructure concerns.
  • Document important aspects because they affect control flow indirectly.
  • Test both intercepted and non-intercepted methods.
  • Understand proxy behavior before debugging missing advice.
  • Use dedicated Spring infrastructure when it already solves the problem.

30. Interview Questions

Q1. What is AOP?

A way to modularize cross-cutting concerns such as logging, auditing and transactions.

Q2. What is Spring Boot's default AOP proxy?

CGLIB.

Q3. How do you switch to JDK proxies?
spring.aop.proxy-target-class=false
Q4. What is an aspect?

A module containing a cross-cutting concern.

Q5. What is a pointcut?

A rule selecting join points where advice should run.

Q6. What is advice?

The action executed at a matched join point.

Q7. What is an AOP proxy?

The proxy through which Spring applies AOP behavior around a target bean.

Q8. Name the common advice types.

Before, After Returning, After Throwing, After, and Around.

Q9. Why avoid unnecessary Around advice?

It is the most powerful advice type and requires managing the continuation of the target invocation.

Q10. Why can self-invocation bypass AOP?

The internal call can go directly to the target object instead of through the Spring proxy.

Q11. Is @EnableAspectJAutoProxy required in Spring Boot?

Not when AspectJ is on the classpath and Boot's AOP auto-configuration applies.

31. Practice Exercises

  1. Create a service and a simple @Aspect.
  2. Add @Before logging.
  3. Add @AfterReturning result logging.
  4. Add @AfterThrowing exception logging.
  5. Create an @Around timing aspect.
  6. Experiment with narrow and broad pointcuts.
  7. Set spring.aop.proxy-target-class=false and inspect behavior.
  8. Create a self-invocation example.
  9. Explain aspect vs advice vs pointcut vs proxy.
  10. Design an auditing aspect for service operations.

32. Quick Cheat Sheet

ConceptRemember
AOPCross-cutting concerns.
AspectThe cross-cutting module.
PointcutWHERE.
AdviceWHAT action.
Join pointIn Spring AOP, method execution.
ProxySpring interception mechanism.
DefaultCGLIB.
JDK proxyspring.aop.proxy-target-class=false.
BeforeBefore target.
After ReturningAfter normal completion.
After ThrowingWhen exception is thrown.
AfterAfter completion.
AroundWraps target execution.
AspectJ auto-proxyAuto-enabled by Boot when AspectJ is on classpath.

33. Memory Map

Spring Boot AOP →

Cross-cutting concern → Aspect → Pointcut → Advice → Proxy → CGLIB default → JDK option → AspectJ auto-proxy → Advice types → Self-invocation → Best practices

34. Final Takeaway

  • Spring Boot provides AOP auto-configuration.
  • CGLIB proxies are the default.
  • Set spring.aop.proxy-target-class=false for JDK proxies.
  • If AspectJ is on the classpath, Boot automatically enables AspectJ auto-proxy support.
  • @EnableAspectJAutoProxy is therefore not required in that situation.
Aspect
  ↓
Pointcut = WHERE
  ↓
Advice = WHAT
  ↓
Spring Proxy
  ↓
Target Method