对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

选择使用哪种 AOP 声明风格

一旦你确定使用切面(aspect)是实现某个需求的最佳方式,那么接下来该如何在 Spring AOP 和 AspectJ 之间进行选择,以及在 Aspect 语言(代码)风格、@AspectJ 注解风格和 Spring XML 风格之间做出决定呢?这些决策受到多种因素的影响,包括应用需求、开发工具以及团队对 AOP 的熟悉程度。spring-doc.cadn.net.cn

Spring AOP 还是完整的 AspectJ?

使用能够满足需求的最简单方案。Spring AOP 比完整的 AspectJ 更简单,因为无需在开发和构建过程中引入 AspectJ 编译器或织入器(weaver)。如果你仅需对 Spring Bean 中的操作执行进行通知(advice),那么 Spring AOP 是合适的选择。但如果你需要对非 Spring 容器管理的对象(例如典型的领域对象)进行通知,则必须使用 AspectJ。此外,如果你希望通知的连接点(join point)不仅仅是简单的方法执行(例如字段的读取或设置等连接点),你也需要使用 AspectJ。spring-doc.cadn.net.cn

当你使用 AspectJ 时,可以选择 AspectJ 语言语法(也称为“代码风格”)或 @AspectJ 注解风格。如果你的设计中切面(aspects)扮演着重要角色,并且你能够使用 Eclipse 的 AspectJ 开发工具(AJDT) 插件,那么 AspectJ 语言语法是首选方案。这种语法更加简洁清晰,因为该语言本身就是专门为编写切面而设计的。如果你不使用 Eclipse,或者你的应用中只有少量切面且它们并不起主要作用,那么你可以考虑使用 @AspectJ 风格,在 IDE 中继续使用常规的 Java 编译方式,并在构建脚本中添加一个切面织入(aspect weaving)阶段。spring-doc.cadn.net.cn

Spring AOP:选择 @AspectJ 还是 XML?

如果你选择使用 Spring AOP,你可以选择 @AspectJ 风格或 XML 风格。 需要考虑各种权衡因素。spring-doc.cadn.net.cn

XML 风格对现有的 Spring 用户来说可能最为熟悉,并且它基于真正的 POJO。当将 AOP 用作配置企业服务的工具时,XML 可能是一个不错的选择(一个很好的判断标准是:你是否认为切入点表达式是你配置的一部分,并且可能需要独立进行修改)。使用 XML 风格时,从配置中可以更清晰地看出系统中存在哪些切面。spring-doc.cadn.net.cn

XML 风格存在两个缺点。首先,它无法将所处理需求的实现完全封装在单一位置。DRY(Don't Repeat Yourself)原则指出,系统中的任何知识都应当有且仅有一个明确、权威的表示。使用 XML 风格时,关于如何实现某个需求的知识被分散到了后备 bean 类的声明和配置文件中的 XML 配置两处。而当你使用 @AspectJ 风格时,这些信息会被封装在一个单独的模块中:即切面(aspect)。其次,XML 风格在表达能力上略逊于 @AspectJ 风格:它仅支持“singleton”(单例)切面实例化模型,并且无法组合在 XML 中声明的具名切入点(named pointcut)。例如,在 @AspectJ 风格中,你可以编写如下代码:spring-doc.cadn.net.cn

@Pointcut("execution(* get*())")
public void propertyAccess() {}

@Pointcut("execution(com.xyz.Account+ *(..))")
public void operationReturningAnAccount() {}

@Pointcut("propertyAccess() && operationReturningAnAccount()")
public void accountPropertyAccess() {}
@Pointcut("execution(* get*())")
fun propertyAccess() {}

@Pointcut("execution(com.xyz.Account+ *(..))")
fun operationReturningAnAccount() {}

@Pointcut("propertyAccess() && operationReturningAnAccount()")
fun accountPropertyAccess() {}

在 XML 风格中,你可以声明前两个切入点:spring-doc.cadn.net.cn

<aop:pointcut id="propertyAccess"
		expression="execution(* get*())"/>

<aop:pointcut id="operationReturningAnAccount"
		expression="execution(com.xyz.Account+ *(..))"/>

XML 方法的缺点在于,你无法通过组合这些定义来定义 accountPropertyAccess 切入点。spring-doc.cadn.net.cn

@AspectJ 风格支持额外的实例化模型和更丰富的切入点(pointcut)组合。它的优势在于将切面保持为一个模块化单元。此外,@AspectJ 切面既可以被 Spring AOP 理解(并使用),也可以被 AspectJ 理解(并使用)。因此,如果你日后决定需要利用 AspectJ 的能力来实现更多需求,可以轻松迁移到经典的 AspectJ 设置。通常情况下,Spring 团队更倾向于在企业服务的简单配置之外,对自定义切面采用 @AspectJ 风格。spring-doc.cadn.net.cn