深入理解 Spring AOP:原理、应用与实战
Spring AOP(面向切面编程)是 Spring 框架的重要模块之一,用于处理日志记录、权限控制、事务管理等通用功能的横切关注点。
本文将从 AOP 的核心概念入手,结合底层原理与代码示例,带你深入掌握 Spring AOP 的强大能力。
一、什么是 AOP?
AOP(Aspect-Oriented Programming)是一种编程范式,用于将横切关注点(如日志、安全、事务)从业务逻辑中分离出来。
横切关注点 vs 纵向业务逻辑
传统开发中,日志、权限、事务控制会散落在每个业务方法中,增加了代码耦合与重复。
AOP 将这些逻辑抽取成 "切面",独立维护,实现"关注点分离"。
二、Spring AOP 的实现方式
Spring AOP 本质是基于动态代理实现的,分为两种方式:
- 基于 JDK 动态代理:代理接口
- 基于 CGLIB 字节码增强:代理类
Spring 自动判断:
- 如果目标类实现接口,则使用 JDK 动态代理
- 否则使用 CGLIB
三、核心概念
概念 | 含义 |
---|---|
JoinPoint | 程序执行的点,例如方法调用 |
Pointcut | 匹配 JoinPoint 的规则 |
Advice | 通知,切面逻辑 |
Aspect | 切面,包含切点与通知 |
Weaving | 将切面应用到目标对象的过程 |
四、注解方式使用 AOP
1. 添加依赖(Spring Boot 已内置)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 编写切面类
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void logPointcut() {}
@Before("logPointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("方法执行前: " + joinPoint.getSignature());
}
@AfterReturning(value = "logPointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("方法执行后: 返回结果 = " + result);
}
}
3. 业务类
@Service
public class UserService {
public String getUser(String id) {
return "用户:" + id;
}
}
4. 启动类开启 AOP
@SpringBootApplication
@EnableAspectJAutoProxy
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
运行后,调用 getUser()
会自动触发切面逻辑。
五、自定义注解 + AOP 实战
1. 创建自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
String value() default "操作日志";
}
2. 使用注解标记方法
@Service
public class OrderService {
@MyLog("下单操作")
public void createOrder(String userId) {
System.out.println("执行下单逻辑");
}
}
3. 切面实现拦截注解
@Aspect
@Component
public class MyLogAspect {
@Around("@annotation(myLog)")
public Object around(ProceedingJoinPoint pjp, MyLog myLog) throws Throwable {
System.out.println("日志开始 - " + myLog.value());
Object result = pjp.proceed();
System.out.println("日志结束");
return result;
}
}
六、Spring AOP 底层原理解析
1. 注册切面类
在 Spring 启动阶段,@Aspect
类被扫描注册为 Bean,并识别其切面方法。
2. Bean 创建阶段
在 AbstractAutoProxyCreator#postProcessAfterInitialization
中,对满足条件的 Bean 生成代理对象。
3. 调用代理对象
代理对象内部维护了一个通知链,当执行目标方法时,会触发所有相关 Advice。
// 简化版逻辑:
public Object invoke(MethodInvocation invocation) throws Throwable {
for (Advice advice : adviceChain) {
advice.before(...);
}
Object result = invocation.proceed();
for (Advice advice : adviceChain) {
advice.after(...);
}
return result;
}
七、AOP 使用建议与注意事项
- 避免对构造函数、final 方法使用 AOP(JDK 动态代理不支持)
- 不建议在同一类中自调用代理方法,AOP 不生效(因为绕过了代理)
- 推荐使用注解 + AOP 结合日志、权限校验、缓存、限流等通用能力
八、总结
Spring AOP 是对横切逻辑解耦的优雅方案,广泛应用于日志、权限、事务等领域。
- 本质基于动态代理实现
- 通过切面定义 Pointcut 与 Advice
- 支持注解、XML、多种方式配置