Mastering Spring AOP: From Basics to Advanced Real‑World Examples

This article introduces Aspect‑Oriented Programming in Spring, explains core concepts such as pointcut, advice, aspect, join point and weaving, and provides step‑by‑step code examples—including a simple @GetMapping logger, a custom permission annotation with multiple aspects, and detailed usage of @Pointcut, @Around, @Before, @After, @AfterReturning and @AfterThrowing annotations—illustrated with diagrams and runnable snippets.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Mastering Spring AOP: From Basics to Advanced Real‑World Examples

Understanding AOP

1.1 What is AOP

AOP (Aspect Oriented Programming) is one of Spring's core concepts, alongside IoC and DI.

It helps separate cross‑cutting concerns such as permission checks, logging, and statistics from business logic, avoiding repetitive code.

By extracting these concerns into aspects, the code becomes cleaner and more maintainable.

1.2 AOP System and Concepts

AOP performs three kinds of work: where to cut in (pointcut), when to cut (before/after), and what to do (advice).

Pointcut

: defines where the aspect is applied. Advice: the action to perform (before, after, around, etc.). Aspect: combination of pointcut and advice. Joint point: a specific execution point, usually a method. Weaving: the process of linking aspect code with target code.

2 AOP Examples

Project code is available at

https://github.com/ThinkMugz/aopDemo

2.1 First Example

All get requests trigger a console message before execution.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Step 1: Create an aspect class

package com.mu.demo.advice;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAdvice {
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    private void logAdvicePointcut() {}

    @Before("logAdvicePointcut()")
    public void logAdvice() {
        System.out.println("get请求的advice触发了");
    }
}

Step 2: Create a controller

package com.mu.demo.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/aop")
public class AopController {
    @GetMapping("/getTest")
    public JSONObject aopTest() {
        return JSON.parseObject("{\"message\":\"SUCCESS\",\"code\":200}");
    }

    @PostMapping("/postTest")
    public JSONObject aopTest2(@RequestParam("id") String id) {
        return JSON.parseObject("{\"message\":\"SUCCESS\",\"code\":200}");
    }
}

Calling the GET endpoint prints the advice message; the POST endpoint does not, confirming the pointcut targets only @GetMapping methods.

2.2 Second Example – Custom Annotation

Define a custom annotation PermissionsAnnotation and two aspect classes to perform sequential permission checks.

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

First Aspect

package com.example.demo;
import com.alibaba.fastjson.*;
import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(1)
public class PermissionFirstAdvice {
    @Pointcut("@annotation(com.mu.demo.annotation.PermissionAnnotation)")
    private void permissionCheck() {}

    @Around("permissionCheck()")
    public Object permissionCheckFirst(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        Long id = ((JSONObject) args[0]).getLong("id");
        if (id < 0) {
            return JSON.parseObject("{\"message\":\"illegal id\",\"code\":403}");
        }
        return joinPoint.proceed();
    }
}

Second Aspect

package com.example.demo;
import com.alibaba.fastjson.*;
import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(0)
public class PermissionSecondAdvice {
    @Pointcut("@annotation(com.example.demo.PermissionsAnnotation)")
    private void permissionCheck() {}

    @Around("permissionCheck()")
    public Object permissionCheckSecond(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String name = ((JSONObject) args[0]).getString("name");
        if (!"admin".equals(name)) {
            return JSON.parseObject("{\"message\":\"not admin\",\"code\":403}");
        }
        return joinPoint.proceed();
    }
}

Applying @PermissionsAnnotation on a controller method triggers both aspects; execution order is controlled by @Order (lower value runs first).

3 AOP‑Related Annotations

3.1 @Pointcut

Defines where an aspect applies. Examples use execution() and annotation() expressions.

@Aspect
@Component
public class LogAspectHandler {
    @Pointcut("execution(* com.mutest.controller..*.*(..))")
    public void pointCut() {}
}

3.2 @Around

Wraps the target method, allowing pre‑ and post‑processing, argument modification, and return‑value alteration.

@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    // pre‑logic
    Object result = joinPoint.proceed();
    // post‑logic
    return result;
}

3.3 @Before

Runs before the matched method, useful for logging or gathering request data.

@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {
    // log method name, URL, IP, etc.
}

3.4 @After

Runs after the matched method, typically for cleanup or final logging.

@After("pointCut()")
public void doAfter(JoinPoint joinPoint) {
    // log completion
}

3.5 @AfterReturning

Captures the method’s return value for further processing.

@AfterReturning(pointcut = "pointCut()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
    // enhance or log result
}

3.6 @AfterThrowing

Handles exceptions thrown by the target method.

@AfterThrowing(pointcut = "pointCut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
    // log exception
}

These annotations together provide a powerful toolkit for modularizing cross‑cutting concerns in Spring applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaaopspringannotationsAspect Oriented Programming
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.