Course topics

By WebNest Studio Engineering Team

Spring Framework Tutorial

Aspect-Oriented Programming (AOP) in Spring

Some concerns in an application — logging, security checks, transaction management, performance monitoring — don't belong to any single class's core responsibility, yet they need to run before, after, or around many different methods scattered across the codebase. Writing this logic manually inside every method leads to duplicated, tangled code. Aspect-Oriented Programming (AOP) solves this by letting you define such "cross-cutting concerns" once, in one place, and have them automatically applied wherever they're needed.

Spring AOP implements this using proxies: when a bean matches an aspect's criteria, Spring wraps it in a dynamically generated proxy object that intercepts method calls, runs the aspect's advice code at the right point, and then delegates to the real method. All of this is configured declaratively using the @Aspect annotation and a small set of advice annotations.

Core AOP Vocabulary

A few terms recur constantly in AOP and are worth knowing precisely.

  • Aspect — a module (a class annotated @Aspect) that encapsulates a cross-cutting concern like logging.
  • Join point — a specific point during execution, such as a method call, where an aspect could apply.
  • Pointcut — an expression that selects which join points (which methods) an aspect's advice applies to.
  • Advice — the actual action taken at a matched join point (e.g. logging before the method runs).

Types of Advice

Spring supports several advice annotations, each describing when relative to the target method the advice code runs.

  • @Before — runs before the matched method executes; cannot prevent the method from running (unless it throws).
  • @After — runs after the method completes, regardless of whether it returned normally or threw an exception (like a finally block).
  • @AfterReturning — runs only after the method completes successfully, with access to its return value.
  • @AfterThrowing — runs only if the method throws an exception, with access to that exception.
  • @Around — wraps the entire method call, and can inspect/modify arguments, skip the call, alter the return value, or measure execution time; it must explicitly call joinPoint.proceed() to invoke the real method.

Writing Pointcut Expressions

Pointcuts are written using AspectJ expression syntax, most commonly the execution() designator, which matches method signatures by pattern: execution(* com.webnest.service.*.*(..)) matches any method, with any return type and any arguments, on any class directly inside the com.webnest.service package. Pointcuts can also match by annotation, e.g. @annotation(org.springframework.transaction.annotation.Transactional) to target methods carrying a specific annotation.

Example

A logging aspect wrapping all service-layer methods with @Around advice

Java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Aspect
@Component
class LoggingAspect {

    @Around("execution(* com.webnest.service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("Entering: " + joinPoint.getSignature());
        Object result = joinPoint.proceed(); // invokes the real method
        long duration = System.currentTimeMillis() - start;
        System.out.println("Exiting: " + joinPoint.getSignature() + " (" + duration + "ms)");
        return result;
    }
}

@Service
class PricingService {
    double calculateTotal(double amount) {
        return amount * 1.1;
    }
}

@EnableAspectJAutoProxy
class AopConfig { }
// Calling pricingService.calculateTotal(100.0) through the Spring-managed proxy
Output
Entering: double com.webnest.service.PricingService.calculateTotal(double)
Exiting: double com.webnest.service.PricingService.calculateTotal(double) (0ms)

Common Mistakes

  • Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing.
  • Calling a method on "this" from within the same class and expecting an aspect to intercept it — Spring AOP proxies only intercept calls made from outside the object, not internal self-invocations.
  • Writing an overly broad pointcut expression (e.g. matching an entire base package) that unintentionally wraps unrelated methods, adding overhead or unexpected logging noise.
  • Forgetting @EnableAspectJAutoProxy (or the Spring Boot auto-configuration equivalent) in a plain Spring application, so @Aspect classes are registered as beans but never actually applied as proxies.

Exercise

Using the lesson's A logging aspect wrapping all service-layer methods with @Around advice example, create a small implementation or design sketch that demonstrates AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects.. Add a test case or scenario that would catch Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing., and describe the expected result.

Show hints
  • Start with Core AOP Vocabulary and compare your approach with A logging aspect wrapping all service-layer methods with @Around advice. Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects. and that it would catch the failure described by Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing..

Quick quiz

1. Which choice is a mistake to avoid in Aspect-Oriented Programming (AOP) in Spring?

  • A. Calling a method on "this" from within the same class and expecting an aspect to intercept it — Spring AOP proxies only intercept calls made from outside the object, not internal self-invocations.
  • B. AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects.
  • C. Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing.
Show answer

C. Avoid this approach: Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing. The lesson recommends: AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects.

Interview questions

A teammate is about to make this mistake: Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing. How would you diagnose and correct it using the lesson's guidance?

Show answer

AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects. Apply this in Core AOP Vocabulary; the example A logging aspect wrapping all service-layer methods with @Around advice shows one way to do it. Avoid Forgetting to call joinPoint.proceed() inside an @Around advice — the target method never actually executes, and any return value expected by the caller is missing. and explain how your implementation or design prevents that failure.

Key Points to Remember

  • AOP separates cross-cutting concerns (logging, security, transactions) from core business logic using aspects.
  • @Aspect classes declare advice methods; pointcut expressions choose which methods the advice applies to.
  • @Before, @After, @AfterReturning, @AfterThrowing, and @Around cover every timing relative to the target method.
  • Spring AOP works via proxies, so self-invocation (a method calling another method on the same object) bypasses the proxy and skips advice.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering