非常棒 👍 阿杰!
Spring AOP 是 Spring 框架的核心之一,经常在日志、权限验证、事务管理、性能监控等功能中使用。
下面我给你一份超详细又实用的 Spring AOP 全面讲解,从概念到底层实现全覆盖,让你彻底搞懂它 👇
🌟 一、什么是 AOP?
AOP(Aspect-Oriented Programming)
中文叫 面向切面编程。
它的目标是:
在不改变业务代码的前提下,统一地对系统功能进行增强。
🧩 举个例子:
假设你有很多业务方法:
public void addUser() { ... }
public void deleteUser() { ... }
public void updateUser() { ... }
如果每个方法前都要打印日志、检查权限、开启事务……
那你就得在每个方法里写重复代码 👇
System.out.println("开始执行...");
checkPermission();
这时候,AOP 出场了。
你只需要定义一个切面(Aspect),告诉 Spring:
“在这些方法执行前,帮我自动加上日志逻辑”。
⚙️ 二、AOP 的核心概念
概念 | 说明 |
---|---|
切面(Aspect) | 横切逻辑模块(比如日志、事务、权限) |
连接点(JoinPoint) | 程序中可以被 AOP 拦截的点(方法调用、异常抛出等) |
切入点(Pointcut) | 实际要被拦截的具体连接点表达式(匹配规则) |
通知(Advice) | 在连接点执行的具体动作(前置、后置、环绕等) |
目标对象(Target) | 被增强的业务类 |
代理对象(Proxy) | 由 Spring AOP 动态创建,用于包装目标对象 |
织入(Weaving) | 把切面逻辑应用到目标对象的过程(运行时完成) |
🧠 三、AOP 的底层原理
Spring AOP 使用两种代理机制:
代理方式 | 触发条件 | 底层实现 |
---|---|---|
JDK 动态代理 | 目标对象实现了接口 | java.lang.reflect.Proxy |
CGLIB 动态代理 | 目标对象没有实现接口 | 通过继承目标类、生成子类 |
✅ Spring Boot 默认自动选择合适的代理方式。
🧱 四、Spring AOP 快速示例
1️⃣ 添加依赖(Spring Boot 已自带)
如果是独立 Spring 项目,需要添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2️⃣ 定义一个业务类
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void addUser(String name) {
System.out.println("业务逻辑:添加用户 " + name);
}
}
3️⃣ 定义一个切面类(Aspect)
package com.example.aspect;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
// 切入点:指定匹配的目标方法(包名 + 类 + 方法)
@Pointcut("execution(* com.example.service.UserService.*(..))")
public void userServiceMethods() {}
// 前置通知
@Before("userServiceMethods()")
public void before() {
System.out.println("🟢 [Before] 方法执行前记录日志");
}
// 后置通知(无论异常与否都会执行)
@After("userServiceMethods()")
public void after() {
System.out.println("🔵 [After] 方法执行结束");
}
// 返回后通知
@AfterReturning("userServiceMethods()")
public void afterReturning() {
System.out.println("✅ [AfterReturning] 方法正常返回");
}
// 异常通知
@AfterThrowing("userServiceMethods()")
public void afterThrowing() {
System.out.println("❌ [AfterThrowing] 方法抛出异常");
}
// 环绕通知(最强大,可以完全控制方法调用)
@Around("userServiceMethods()")
public Object around(org.aspectj.lang.ProceedingJoinPoint pjp) throws Throwable {
System.out.println("⚙️ [Around-Before] 环绕前逻辑");
Object result = pjp.proceed(); // 执行目标方法
System.out.println("⚙️ [Around-After] 环绕后逻辑");
return result;
}
}
4️⃣ 启动类(确保 AOP 生效)
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy // 启用 AOP 代理功能
public class AopDemoApplication {
public static void main(String[] args) {
var context = SpringApplication.run(AopDemoApplication.class, args);
var userService = context.getBean("userService", com.example.service.UserService.class);
userService.addUser("阿杰");
}
}
5️⃣ 控制台输出结果
🟢 [Before] 方法执行前记录日志
⚙️ [Around-Before] 环绕前逻辑
业务逻辑:添加用户 阿杰
⚙️ [Around-After] 环绕后逻辑
✅ [AfterReturning] 方法正常返回
🔵 [After] 方法执行结束
🚀 你会发现,AOP 自动帮你在目标方法前后插入了逻辑,而你完全没改业务代码!
🧩 五、常见切入点表达式
表达式 | 说明 |
---|---|
execution(* com.example.service.*.*(..)) | 匹配 service 包下所有方法 |
execution(* com.example..*(..)) | 匹配 com.example 包及子包下所有方法 |
@annotation(org.springframework.transaction.annotation.Transactional) | 匹配带 @Transactional 注解的方法 |
within(com.example.controller..*) | 匹配某个包内所有类的方法 |
args(String, ..) | 匹配第一个参数为 String 的方法 |
🧰 六、五种通知类型对比
通知类型 | 注解 | 触发时机 | 是否能阻止执行 |
---|---|---|---|
前置通知 | @Before | 方法执行前 | ❌ |
后置通知 | @After | 方法执行后(无论异常) | ❌ |
返回通知 | @AfterReturning | 方法正常返回后 | ❌ |
异常通知 | @AfterThrowing | 方法抛异常后 | ❌ |
环绕通知 | @Around | 方法执行前后 | ✅(可以决定是否继续执行) |
⚡ 七、AOP 常见应用场景
场景 | 示例 |
---|---|
日志记录 | 记录接口调用、方法耗时 |
权限验证 | 判断当前用户是否有访问权限 |
事务管理 | @Transactional 就是 AOP 实现的 |
缓存管理 | 缓存读取 / 更新拦截 |
性能监控 | 统计接口耗时 |
异常处理 | 全局捕获统一格式输出 |
🔍 八、Spring AOP vs AspectJ
对比项 | Spring AOP | AspectJ |
---|---|---|
实现方式 | 动态代理(运行时织入) | 编译期或类加载期织入 |
性能 | 略低 | 更高 |
使用复杂度 | 简单(Spring Boot 开箱即用) | 较复杂 |
应用场景 | 业务级增强 | 系统级增强(如编译期检查) |
Spring AOP 默认使用 AspectJ 的注解语法,但不需要 AspectJ 编译器。
🧭 九、总结速查表
概念 | 英文名 | 简述 |
---|---|---|
切面 | Aspect | 封装横切逻辑的类 |
通知 | Advice | 具体执行逻辑(前置、后置等) |
切入点 | Pointcut | 定义哪些方法要被拦截 |
连接点 | JoinPoint | 程序执行的具体点 |
织入 | Weaving | 将切面逻辑应用到目标对象 |
代理对象 | Proxy | 被增强的对象 |
常用注解 | @Aspect , @Before , @Around 等 | |
启用注解 | @EnableAspectJAutoProxy |
🧠 十、扩展建议
你可以练习做一个实用项目,比如:
✅ “AOP 日志监控系统”
功能:
- 拦截所有
@RestController
的接口; - 打印方法名、参数、执行时间、返回值;
- 用
@Around
实现; - 自动写入日志文件。
是否希望我帮你写出这个 AOP 接口调用日志监控系统(含完整代码 + 输出示例)?
能直接复制进你的 Spring Boot 项目运行。
发表回复