Skip to content

Spring AOP 编程 (Aspect Oriented Programming with Spring)

面向切面编程(AOP)通过提供另一种思考程序结构的方式,补足了面向对象编程(OOP)的不足。在 OOP 中,模块化的核心单位是 类(Class),而在 AOP 中,模块化的单位则是 切面(Aspect)。切面使得那些跨越多个类型和对象关注点(Concern,例如事务管理)的模块化成为可能。(在 AOP 文献中,这些关注点通常被称为“横切(Crosscutting)”关注点。)

Spring 的核心组件之一就是 AOP 框架。虽然 Spring IoC 容器并不依赖于 AOP(这意味着如果你不想用,完全可以不用),但 AOP 极好地补充了 Spring IoC,共同提供了一个功能及其强大的中间件解决方案。

Spring AOP 与 AspectJ 切入点

Spring 通过 基于 Schema 的方式@AspectJ 注解风格,提供了简单而强大的编写自定义切面的方式。

这两种风格都支持全类型通知(Fully Typed Advice)并利用 AspectJ 切入点语言,同时仍然使用 Spring AOP 进行织入(Weaving)。

本章讨论基于 Schema 和基于 @AspectJ 的 AOP 支持。底层的 AOP 支持将在下一章中讨论。

Spring 框架中使用 AOP 的主要目的如下:

  • 提供声明式企业服务:其中最重要的服务是声明式事务管理
  • 允许用户实现自定义切面:使用 AOP 来补足 OOP 的使用。

提示

如果你只对通用的声明式服务或其他预包装的中间件服务(如对象池)感兴趣,则不需要直接操作 Spring AOP,可以跳过本章的大部分内容。


补充教学

1. 为什么要学习 AOP?(大白话版)

想象你在写一个电商系统。在执行“下单”、“退款”、“修改个人信息”这些业务代码之前,你都需要做三件事:

  1. 权限检查:用户登录了吗?
  2. 日志记录:记录操作内容。
  3. 性能监控:记录这个方法跑了多久。

如果你用 OOP(面向对象),你得在每个方法里重复写这些代码。这就像是在每一个文件夹里都粘一个同样的标签。 AOP 的逻辑是:我定义一个“切面”(Aspect),告诉系统:“凡是以 save 开头的方法,在执行前都帮我跑一下权限检查”。业务代码从此变得干干净净,只管业务逻辑。

2. AOP 与 OOP 的关系

  • OOP(纵向):像树状结构,封装了属性和行为,解决了“我是谁、我能做什么”的问题。
  • AOP(横向):像在原来的树桩上横向切了一刀,解决了“在哪些地方、做什么额外操作”的问题。 它们不是替代关系,而是补足关系

3. Spring AOP vs. 原生 AspectJ

  • Spring AOP:基于动态代理。优点是简单,不需要特殊的编译器。缺点是只能拦截方法,且同一个类内部方法互相调用时会失效。
  • AspectJ:功能最强大的 AOP 框架。基于字节码修改。优点是能拦截任何东西(属性访问、构造函数等),性能极高。缺点是需要使用专门的 ajc 编译器。 总结:Spring AOP 满足了 95% 的业务需求,它在底层借鉴了 AspectJ 的切点表达式语法,但在执行上采用了动态代理。

4. 关键术语提前看(核心三剑客)

  • 切面 (Aspect):你要实现的“通用功能”(如:事务、日志)。
  • 切点 (Pointcut):你要在“哪里”搞事情(如:所有 Service 层的方法)。
  • 通知 (Advice):你要在“什么时候”搞事情(如:方法执行前、执行后、报错时)。

5. 一个经典的“坑”:内部调用

如果在同一个类中,方法 A 调用了方法 B,即使你给方法 B 配置了切面(如事务),切面也不会起作用。这是因为 Spring AOP 是基于代理的,内部调用绕过了代理对象。这是面试中经常被问到的“AOP 失效场景”之一。

Based on Spring Framework.