Spring AOP - Aspect Oriented Programming
AOP Concepts
Aspect-Oriented Programming (AOP) is a programming paradigm that allows you to separate cross-cutting concerns (like logging, security, transactions) from your business logic. Instead of scattering the same code across many classes, you define it once in an Aspect.
| Term | Description |
|---|---|
| Aspect | A class containing cross-cutting logic (annotated with @Aspect) |
| Advice | The action taken at a join point (@Before, @After, @Around, etc.) |
| Join Point | A point in program execution (method call, exception throw) |
| Pointcut | An expression that matches join points (which methods to intercept) |
| Weaving | Linking aspects with application objects (Spring does this at runtime) |
package com.example.aspect;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// Pointcut: matches all methods in service package
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
// @Before: runs BEFORE the method
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("[BEFORE] " + joinPoint.getSignature().getName()
+ " called with args: " + java.util.Arrays.toString(joinPoint.getArgs()));
}
// @After: runs AFTER the method (regardless of outcome)
@After("serviceLayer()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("[AFTER] " + joinPoint.getSignature().getName() + " completed");
}
// @AfterReturning: runs after successful return
@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("[AFTER_RETURNING] " + joinPoint.getSignature().getName()
+ " returned: " + result);
}
// @AfterThrowing: runs when method throws exception
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
System.err.println("[AFTER_THROWING] " + joinPoint.getSignature().getName()
+ " threw: " + ex.getMessage());
}
// @Around: wraps the method - most powerful advice
@Around("execution(* com.example.service.*.*(..)) && @annotation(com.example.annotation.Timed)")
public Object measureTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = joinPoint.proceed(); // Execute the actual method
long duration = System.currentTimeMillis() - start;
System.out.println("[TIMED] " + joinPoint.getSignature().getName()
+ " took " + duration + "ms");
return result;
} catch (Exception e) {
System.err.println("[TIMED] " + joinPoint.getSignature().getName()
+ " failed after " + (System.currentTimeMillis() - start) + "ms");
throw e;
}
}
}
Pointcut Expressions
@Aspect
@Component
public class PointcutExamples {
// All methods in UserService
@Pointcut("execution(* com.example.service.UserService.*(..))")
public void userServiceMethods() {}
// All public methods in any class
@Pointcut("execution(public * *(..))")
public void publicMethods() {}
// Methods starting with "get"
@Pointcut("execution(* com.example..get*(..))")
public void getterMethods() {}
// Methods with @Transactional annotation
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalMethods() {}
// All beans in service package
@Pointcut("within(com.example.service.*)")
public void servicePackage() {}
// Combine pointcuts
@Pointcut("servicePackage() && publicMethods()")
public void publicServiceMethods() {}
// Use combined pointcut
@Before("publicServiceMethods()")
public void logPublicServiceCall(JoinPoint jp) {
System.out.println("Calling: " + jp.getSignature());
}
// Transaction aspect example
@Around("@annotation(com.example.annotation.RequiresTransaction)")
public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Starting transaction...");
try {
Object result = pjp.proceed();
System.out.println("Committing transaction...");
return result;
} catch (Exception e) {
System.out.println("Rolling back transaction...");
throw e;
}
}
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.