选择使用哪种AOP声明风格

一旦您决定使用切面来实现特定需求,您如何在使用Spring AOP或AspectJ以及切面语言(代码)风格、@AspectJ注解风格或Spring XML风格之间做出选择?这些决策受多种因素影响,包括应用程序需求、开发工具以及团队对AOP的熟悉程度。

Spring AOP还是完整的AspectJ?

使用最简单的方法。Spring AOP比使用完整的AspectJ更简单,因为无需将AspectJ编译器/织入器引入到您的开发和构建过程中。如果您只需要通知Spring bean上的操作执行,Spring AOP是正确的选择。如果您需要通知Spring容器未管理的对象(例如领域对象),则需要使用AspectJ。如果您希望通知除简单方法执行之外的连接点(例如字段获取或设置连接点等),也需要使用AspectJ。

当您使用AspectJ时,您可以选择AspectJ语言语法(也称为“代码风格”)或@AspectJ注解风格。如果切面在您的设计中扮演重要角色,并且您能够在Eclipse中使用AspectJ开发工具(AJDT)插件,那么AspectJ语言语法是首选选项。它更清晰、更简单,因为该语言是专门为编写切面而设计的。如果您不使用Eclipse,或者只有少数在应用程序中不起主要作用的切面,您可能希望考虑使用@AspectJ风格,坚持在IDE中进行常规Java编译,并在构建脚本中添加一个切面织入阶段。

使用@Spring AOP还是XML?

如果您选择使用Spring AOP,您可以选择@AspectJ或XML风格。有各种权衡考虑。

XML风格可能对现有Spring用户最为熟悉,并且由真正的POJO支持。当将AOP作为配置企业服务的工具时,XML可能是一个不错的选择(一个好的测试是您是否认为切入点表达式是您可能想要独立更改的配置的一部分)。使用XML风格时,从您的配置中清楚地看出系统中存在哪些切面。

XML风格有两个缺点。首先,它不能完全封装它所处理的需求的实现在一个地方。DRY原则指出系统中任何知识片段应该有一个单一、明确、权威的表示。使用XML风格时,如何实现需求的知识分散在支持bean类的声明和配置文件中的XML中。当您使用@AspectJ风格时,这些信息封装在一个单一模块中:切面。其次,XML风格在表达能力上略逊于@AspectJ风格:仅支持“singleton”切面实例化模型,并且无法组合在XML中声明的命名切入点。例如,在@AspectJ风格中,您可以编写如下内容:

  • Java

  • Kotlin

@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风格中,您可以声明前两个切入点:

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

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

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

@AspectJ风格支持额外的实例化模型和更丰富的切入点组合。它的优势在于将切面作为一个模块化单元。另外,@AspectJ风格的切面既可以被Spring AOP理解(因此可消费),也可以被AspectJ理解。因此,如果以后决定需要AspectJ的功能来实现额外的需求,可以轻松迁移到经典的AspectJ设置。总的来说,Spring团队更倾向于将@AspectJ风格用于超出企业服务简单配置的自定义切面。