Skip to content

Spring AOP

Published: at 11:00 AM
Loading...

1. Spring AOP Annotation Explanation

@Before

Executed before the target method runs. Commonly used for logging, parameter validation, permission checks, etc.
When the defined pointcut expression is matched, Spring executes this method before calling the target method.

@Around

An around advice wraps the entire execution process of the target method.
By calling ProceedingJoinPoint.proceed() explicitly, it can add custom logic before and after the method execution.
This is the most flexible advice type — it can control whether the method executes, modify parameters, or process return values.

@After

Executed after the target method finishes, regardless of whether an exception occurred.
Similar to a finally block, it’s often used for resource cleanup or general logging.

@AfterReturning

Executed only when the target method returns normally.
If the method throws an exception, this advice will not run.
Often used to process the return value or log successful execution.

@AfterThrowing

Executed when the target method throws an exception.
Useful for logging exception details, sending alerts, or collecting error statistics.

@Pointcut

@Pointcut is used to extract pointcut expressions, which define where advices apply.
Instead of writing execution(...) repeatedly, you can define it once as a method and reuse it across multiple advices for better readability and maintainability.

Example:

@Pointcut("execution(* top.mygld.demo.service.impl..*(..))")
public void serviceMethods() {}

Then reuse it:

@Before("serviceMethods()")
@After("serviceMethods()")

2. Spring AOP Example (Using @Pointcut Extraction)

package top.mygld.demo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class TestAspect {

    // Extracted pointcut expression matching all methods under service.impl package
    @Pointcut("execution(* top.mygld.demo.service.impl..*(..))")
    public void serviceMethods() {}

    @Before("serviceMethods()")
    public void before() {
        log.info("before ....");
    }

    @Around("serviceMethods()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("around ... before ....");
        Object result = joinPoint.proceed();
        log.info("around ... after ....");
        return result;
    }

    @After("serviceMethods()")
    public void after() {
        log.info("after ....");
    }

    @AfterReturning("serviceMethods()")
    public void afterReturning() {
        log.info("afterReturning ....");
    }

    @AfterThrowing("serviceMethods()")
    public void afterThrowing() {
        log.info("afterThrowing ....");
    }
}

Execution order when the method runs normally: @Around → @Before → method execution → @AfterReturning → @After → @Around

Execution order when the method throws an exception: @Around → @Before → method execution → @AfterThrowing → @After → @Around

Using these annotations together allows injecting logic at different stages — ideal for unified logging, monitoring, or security. @Pointcut makes the structure cleaner by allowing multiple advices to share the same matching rules.

If different methods need their own pointcut expressions, they can be written separately, for example:

@AfterReturning("execution(* top.mygld.demo.dao.impl..*(..))")
public void afterReturning(){
    log.info("afterReturning ....");
}

@AfterThrowing("execution(* top.mygld.demo.service.impl..*(..))")
public void afterThrowing(){
    log.info("afterThrowing ....");
}

3. Multiple Advice Execution Order

In Spring AOP, the execution order of multiple advices follows these rules:

Within the same aspect class:

Between different aspect classes:

Example:

@Aspect
@Component
@Order(5)
public class LogAspect1 {}

@Aspect
@Component
@Order(7)
public class LogAspect2 {}

Execution overview:

Outer aspect @Around

  Inner aspect @Around

    @Before (outer to inner)

     Target method

    @AfterReturning / @AfterThrowing (inner to outer)

    @After (inner to outer)

  Inner @Around ends

Outer @Around ends

This mechanism ensures predictable and precisely controlled AOP execution order when multiple aspects or advices exist.

4. Pointcut Expressions

execution

execution matches based on method return type, package name, class name, method name, and parameters.

Syntax: execution(modifier? return-type package.class.?method(parameters) throws exception?) Parts marked with ? are optional.

* matches any single element — return type, package, class, method, or parameter.

execution(* top.*.service.*.update*(*))

.. matches multiple consecutive elements — nested packages or any number of parameters.

execution(* top.mygld..UserService.*(..))

annotation

Matches methods annotated with a specific annotation. Example annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogOperation {}

Applied to a method:

@LogOperation
@Override
public List<User> findAll() {
    return userDao.findAll();
}

Used in an aspect:

@Before("@annotation(top.mygld.demo.anno.LogOperation)")
public void before(){
    log.info("before");
}

In IDEs like IntelliJ, the m icon can confirm the match visually.

5. JoinPoint

In Spring, JoinPoint abstracts a connection point, allowing access to method execution details such as class name, method name, and arguments.

For @Around, use ProceedingJoinPoint; for the other four types, use JoinPoint, which is the parent of ProceedingJoinPoint.

Example:

@Before("@annotation(top.mygld.demo.anno.LogOperation)")
public void before(JoinPoint jp){
    log.info("before");
    // 1. Get target object
    Object target = jp.getTarget();
    log.info("target: {}", target);
        
    // 2. Get target class
    String name = target.getClass().getName();
    log.info("name: {}", name);
        
    // 3. Get target method
    String methodName = jp.getSignature().getName();
    log.info("methodName: {}", methodName);
        
    // 4. Get method arguments
    Object[] args = jp.getArgs();
    log.info("args: {}", args);
}

Previous Post
Injecting Third-Party Beans into IoC Container
Next Post
volatile Keyword