文章目录
-
- 一、AOP核心简介
- 二、SpringBoot快速实现AOP(注解版)
-
- [1. 引入核心依赖](#1. 引入核心依赖)
- [2. 编写切面类(五种通知完整示例)](#2. 编写切面类(五种通知完整示例))
- [3. 测试接口](#3. 测试接口)
- [4. 通知执行顺序](#4. 通知执行顺序)
- [三、传统Spring AOP vs SpringBoot AOP核心区别](#三、传统Spring AOP vs SpringBoot AOP核心区别)
-
- [1. 核心差异汇总](#1. 核心差异汇总)
- [四、SpringBoot AOP切面 vs 自定义注解(生产重点)](#四、SpringBoot AOP切面 vs 自定义注解(生产重点))
-
- [1. 核心关系](#1. 核心关系)
- [2. 两种方式对比](#2. 两种方式对比)
- 五、实战1:纯AOP全局拦截(仅演示,不推荐生产)
- 六、实战2:AOP+自定义注解(生产标准写法)
-
- [1. 创建自定义标记注解](#1. 创建自定义标记注解)
- [2. 切面拦截该注解](#2. 切面拦截该注解)
- [3. 业务接口按需使用](#3. 业务接口按需使用)
- 七、最终生产总结
一、AOP核心简介
AOP(面向切面编程)是Spring两大核心之一,核心作用就是不改动业务代码,就能对方法做统一增强,实现业务逻辑与公共逻辑解耦。常用于统一日志、接口耗时统计、权限校验、事务管理、操作记录等场景。
核心四要素:切点 (要拦截哪些方法)、切面 (增强处理类)、通知 (前后/环绕/异常等增强逻辑)、连接点(被拦截的目标方法)。
二、SpringBoot快速实现AOP(注解版)
1. 引入核心依赖
SpringBoot无需繁琐配置,仅需引入AOP启动器,自动完成装配。
xml
<!-- SpringBoot AOP核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 编写切面类(五种通知完整示例)
@Aspect标记切面类,@Component交给容器管理,通过切点匹配目标方法,配置不同通知完成增强。
java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAndTimeAspect {
// 切点:拦截controller包下所有方法
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void controllerPointCut(){}
// 前置通知:方法执行前
@Before("controllerPointCut()")
public void beforeAdvice(){
System.out.println("【前置通知】方法开始执行");
}
// 后置通知:无论是否异常,执行完毕都执行
@After("controllerPointCut()")
public void afterAdvice(){
System.out.println("【后置通知】方法执行结束");
}
// 返回通知:方法正常返回后执行
@AfterReturning(pointcut = "controllerPointCut()",returning = "result")
public void afterReturningAdvice(Object result){
System.out.println("【返回通知】返回值:" + result);
}
// 异常通知:方法报错时执行
@AfterThrowing(pointcut = "controllerPointCut()",throwing = "e")
public void afterThrowingAdvice(Exception e){
System.out.println("【异常通知】异常信息:" + e.getMessage());
}
// 环绕通知:功能最强,手动控制方法执行前后逻辑
@Around("controllerPointCut()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
// 执行目标方法
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("【环绕通知】方法耗时:" + (endTime - startTime) + "ms");
return result;
}
}
3. 测试接口
java
@RestController
public class AopTestController {
@GetMapping("/aop/test")
public String aopTest(){
System.out.println("业务方法执行中");
return "AOP执行成功";
}
}
4. 通知执行顺序
正常执行:环绕前置 → 前置通知 → 目标方法 → 返回通知 → 后置通知 → 环绕后置。
异常执行:环绕前置 → 前置通知 → 方法报错 → 异常通知 → 后置通知。
三、传统Spring AOP vs SpringBoot AOP核心区别
两者底层原理、切点规则、通知逻辑完全一样,核心区别仅在配置和使用方式。
1. 核心差异汇总
-
配置方式:Spring AOP必须写XML配置,繁琐冗余;SpringBoot AOP零XML,纯注解开箱即用。
-
依赖管理:Spring需手动导入多个Jar、处理版本冲突;SpringBoot只需一个启动器,自动管控版本。
-
代理开启:Spring需手动配置AOP自动代理标签;SpringBoot默认自动开启,无需手动配置。
-
适用场景:Spring AOP仅用于老旧SSM项目维护;SpringBoot AOP是新项目、微服务标配。
四、SpringBoot AOP切面 vs 自定义注解(生产重点)
1. 核心关系
AOP切面 :干活的拦截器,负责方法增强逻辑;自定义注解:标记开关,只负责筛选哪些方法需要拦截。
两者不是二选一,生产标配:AOP切面 + 自定义注解组合使用。
2. 两种方式对比
| 对比维度 | 纯AOP按包名拦截(execution) | AOP+自定义注解(精准拦截) |
|---|---|---|
| 拦截范围 | 全局批量拦截,范围大 | 只拦截加注解的方法,精准可控 |
| 误拦截风险 | 高,容易拦截无关方法 | 无,不加注解不生效 |
| 适用场景 | 全局耗时、基础统一日志 | 操作日志、权限、限流、数据脱敏 |
| 生产推荐 | 少用、不推荐 | 首选、企业标准 |
五、实战1:纯AOP全局拦截(仅演示,不推荐生产)
按包名一刀切,所有接口都拦截,无法单独控制,容易产生垃圾日志。
java
@Aspect
@Component
public class AllApiLogAspect {
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void pointcut(){}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("接口入参:" + Arrays.toString(joinPoint.getArgs()));
Object result = joinPoint.proceed();
System.out.println("接口出参:" + result);
return result;
}
}
六、实战2:AOP+自定义注解(生产标准写法)
1. 创建自定义标记注解
java
import java.lang.annotation.*;
// 仅标记方法、运行时生效
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperateLog {
String value() default ""; // 记录操作描述
}
2. 切面拦截该注解
java
@Aspect
@Component
public class OperateLogAspect {
// 只拦截加了@OperateLog注解的方法
@Pointcut("@annotation(com.example.demo.annotation.OperateLog)")
public void operateLogPointcut(){}
@Around("operateLogPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("===== 记录重要操作日志 =====");
System.out.println("操作方法:" + joinPoint.getSignature().getName());
System.out.println("请求参数:" + Arrays.toString(joinPoint.getArgs()));
Object result = joinPoint.proceed();
System.out.println("操作返回结果:" + result);
return result;
}
}
3. 业务接口按需使用
java
@RestController
public class UserController {
// 普通查询:不加注解 → 不记录日志
@GetMapping("/user/get")
public String getUser(){
return "查询用户";
}
// 重要操作:加注解 → AOP自动记录日志
@OperateLog("删除用户操作")
@GetMapping("/user/delete")
public String deleteUser(){
return "删除成功";
}
}
七、最终生产总结
-
简单全局通用功能,可少量使用纯AOP包名拦截;
-
业务特殊增强功能,一律使用AOP+自定义注解,精准可控、好维护;
-
SpringBoot新项目只用注解AOP,传统Spring XML配置仅作老旧项目维护使用。