选择使用哪种 AOP 声明风格

当你确定切面是实现某项需求的最佳方式后,如何在 Infra AOP 与 AspectJ 之间, 以及在 Aspect 语言(代码)风格、@AspectJ 注解风格或 Infra XML 风格之间做选择? 这些决策会受到应用需求、开发工具和团队对 AOP 熟悉程度等因素影响。

Infra AOP 还是完整 AspectJ?

选择可行的最简单方案。Infra AOP 比完整的 AspectJ 更简单,因为不需要在开发与构建 流程中引入 AspectJ 编译器/织入器。如果只需要对 Infra bean 上的操作执行进行通知, Infra AOP 是正确选择。如果需要对不由 Infra 容器管理的对象(通常是领域对象)进行通知, 就需要使用 AspectJ。若希望对方法执行之外的连接点(例如字段 get/set 等)进行通知, 也需要使用 AspectJ。

使用 AspectJ 时,可选择 AspectJ 语言语法(也称“代码风格”)或 @AspectJ 注解风格。 如果切面在设计中占较大比重,且可以使用 Eclipse 的 AspectJ Development Tools (AJDT) 插件, AspectJ 语言语法是首选,因为它专为编写切面而设计,语义更清晰、表达更简洁。 如果不使用 Eclipse,或只需要少量切面且其在应用中不占主要地位,可以考虑使用 @AspectJ 风格,在 IDE 中保持常规 Java 编译,并在构建脚本中加入切面织入阶段。

Infra AOP 使用 @AspectJ 还是 XML?

如果选择使用 Infra AOP,你可以在 @AspectJ 与 XML 风格之间选择。 二者存在若干权衡。

XML 风格可能最符合既有 Infra 用户的习惯,并由真正的 POJO 作为后端实现。 当将 AOP 用作配置企业级服务的工具时,XML 是不错的选择 (一个好判断标准是:你是否希望将切点表达式视为独立于代码、可单独变更的配置)。 采用 XML 风格时,你可以更清晰地从配置中看到系统中存在哪些切面。

XML 风格有两个缺点。第一,它无法把需求的实现完全封装在单一位置。DRY 原则要求系统中 任何知识只有唯一、明确且权威的表达。使用 XML 风格时,需求实现的知识被分散在后端 bean 类的声明以及配置文件中的 XML 里。使用 @AspectJ 风格时,这些信息被封装在一个模块中, 即切面本身。第二,XML 风格的表达能力略逊于 @AspectJ:只支持“单例”切面实例化模型, 且无法组合在 XML 中声明的命名切点。例如,在 @AspectJ 风格中可以写如下内容:

  • Java

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

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

@Pointcut("propertyAccess() && operationReturningAnAccount()")
public void accountPropertyAccess() {}

在 XML 风格中可以声明前两个切点:

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

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

XML 方式的缺点是无法通过组合这些定义来声明 accountPropertyAccess 切点。

@AspectJ 风格支持更多实例化模型与更丰富的切点组合。它的优势在于让切面作为模块单元存在。 它还具有 @AspectJ 切面既可被 Infra AOP 理解也可被 AspectJ 理解的优势。因此,如果以后 需要 AspectJ 的能力来满足更多需求,可以轻松迁移到经典 AspectJ 方案。总体而言, Infra 团队更偏好将 @AspectJ 风格用于除简单企业服务配置之外的自定义切面。