Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Aspect-Oriented Programming in Spring: Core Concepts and Practical Implementation

Tech Apr 17 9

Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by enabling modularization of cross-cutting concerns — behaviors that span multiple classes, such as logging, security, or transaction management. Unlike OOP, which structures code around objects and inheritance, AOP allows developers to inject shared logic without modifying core business code — aligning with Spring’s non-invasive design philosophy.

Key AOP Terminology

  • Join Point: Any identifiable point during program execution — typically method invocation in Spring AOP.
  • Pointcut: A predicate that matches join points. It can target a single method or a group (e.g., all methods starting with "get" or ending with "Dao").
  • Advice: The action taken at a pointcut — the actual logic to be injected (e.g., timing, logging). Represented as methods within an advice clas.
  • Aspect: A modular unit combining pointcuts and advice.

Annotation-Based AOP Setup

Add the AspectJ Weaver dependency:

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

Define a sample DAO interface and implementation:

public interface DataRepository {
    void create();
    void modify();
    void remove();
    int fetch();
}

@Repository
public class DataRepositoryImpl implements DataRepository {
    public void create() {
        for (int i = 0; i < 10000; i++) {
            System.out.println("Creating record...");
        }
    }

    public void modify() { System.out.println("Modifying record..."); }
    public void remove() { System.out.println("Removing record..."); }
    public int fetch() { return 42; }
}

Create an aspect class to measure execution time:

@Component
@Aspect
public class PerformanceMonitor {

    @Pointcut("execution(* com.example.repo.DataRepository.*(..))")
    private void repositoryMethods() {}

    @Around("repositoryMethods()")
    public Object benchmark(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long duration = System.currentTimeMillis() - start;
        System.out.println("Execution took: " + duration + "ms");
        return result;
    }
}

Enable AOP in you're configuration class:

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {}

AOP Proxy Workflow

  1. Spring container initializes and scans for aspects.
  2. For each bean, Spring checks if any methods match defined pointcuts.
  3. If matched, Spring creates a proxy wrapping the original (target) object.
  4. Method calls on the proxy trigger both the original logic and the advice.

Pointcut Expression Syntax

Format: execution([modifiers] [return-type] [package].[class].[method]([params]) [throws])

Examples with wildcards:

  • execution(* com.example.*.UserService.find*(..)) — Matches any find-prefixed method in UserService under com.example.
  • execution(* com..*.Service+.*(..)) — Matches all methods in Service interfaces or their subclasses.

Advice Types

  • @Before — Runs before the target method.
  • @After — Runs after the target method, regardless of outcome.
  • @Around — Wraps the method, allowing control over execution and return values (most powerful).
  • @AfterReturning — Runs only if the method completes successfully.
  • @AfterThrowing — Runs only if the method throws a exception.

Accessing Runtime Data in Advice

Use JoinPoint or ProceedingJoinPoint to access method arguments:

@Before("repositoryMethods()")
public void logArgs(JoinPoint jp) {
    System.out.println("Arguments: " + Arrays.toString(jp.getArgs()));
}

Capture return values via @AfterReturning:

@AfterReturning(pointcut = "repositoryMethods()", returning = "result")
public void logResult(Object result) {
    System.out.println("Returned: " + result);
}

Handle exceptions with @AfterThrowing:

@AfterThrowing(pointcut = "repositoryMethods()", throwing = "ex")
public void logException(Throwable ex) {
    System.out.println("Exception: " + ex.getMessage());
}

Practical Example: Input Sanitization

Automatically trim whitespace from string parameters:

@Around("execution(* com.example.service.*.*(..))")
public Object sanitizeStrings(ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();
    for (int i = 0; i < args.length; i++) {
        if (args[i] instanceof String) {
            args[i] = ((String) args[i]).trim();
        }
    }
    return pjp.proceed(args);
}

Tags: spring

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.