Spring AOP 与 AspectJ 的关系

结论先行:两者不是"一个框架的两个名字"——AspectJ 是独立完整的 AOP 框架(语言级扩展,编译期/类加载期织入字节码,支持字段、构造器、静态初始化等更多连接点,可以切非 Spring 管理的任何 Java 类);Spring AOP 只是 Spring 容器内的代理式 AOP 子集,它借用了 AspectJ 的注解与切点表达式语法(@Aspect/@Pointcut/execution),但底层仍是运行期 JDK/CGLIB 动态代理,只作用于容器 Bean 的 public 方法执行。

一、对比表

对比项Spring AOPAspectJ
织入方式运行期动态代理(生成代理对象)编译期织入 / 加载期织入(LTW,改字节码)
连接点范围仅 Bean 的 public 方法执行方法、字段读写、构造器、static 初始化、异常处理等
可切对象仅 Spring 容器管理的 Bean任意 Java 类(含第三方 jar 内类)
依赖spring-aop / spring-aspectsaspectjweaver、aspectjrt(或编译器插件)
使用难度低,工程主流高,配置重
适用事务、缓存、日志、权限等业务切面需要织入非 Spring 对象、字段级或静态资源切面

二、代码(注意语法来源)

@Aspect                       // 注解语法来自 AspectJ,但运行时由 Spring AOP 代理实现
@Component
public class MetricsAspect {
    @Around("@annotation(com.demo.annotation.Metrics)")   // 切点表达式也是 AspectJ 语法
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        return pjp.proceed();
    }
}
// 结论:@EnableAspectJAutoProxy 只是开启 Spring 自己的代理切面,并不会真的启动 AspectJ

三、选型建议

  • 事务/缓存/安全/日志等常规横切关注点 → Spring AOP 足够,零额外依赖、与 IoC 无缝整合;
  • 需要织入第三方/非 Spring 管理的类、字段级或构造器切面 → 再引入 AspectJ(LTW 或编译期织入);
  • 已有 AspectJ 基建、追求极致织入能力的团队可全程 AspectJ,但绝大多数业务系统没有必要。

常见追问 / 记忆点

  • 追问 1:什么时候才需要真 AspectJ?答:要织入非 Spring 管理的类、要对字段/构造器做切面、或目标类 final 无法被代理时,再考虑 AspectJ 加载期织入(-javaagent:aspectjweaver 或 aop.xml)。
  • 追问 2:Spring Boot 需要手动开 AOP 吗?答:引入 spring-boot-starter-aop 后自动配置生效,无需 @EnableAspectJAutoProxy(它已内置)。
  • 追问 3:为什么 Spring 不直接用 AspectJ?答:代理方案零学习成本、与 IoC 无缝整合,覆盖 95% 的企业切面需求,代价是牺牲一部分连接点能力。
  • 记忆点:"Spring AOP 是代理,AspectJ 是织入;Spring 只借了 AspectJ 的语法,没借它的运行时"。
笔记加载中…