对 AOP 的理解与应用

面向切面编程(AOP,Aspect-Oriented Programming)允许开发者将与业务逻辑无关的功能(如事务管理、日志记录和权限控制等)封装为独立的模块。这不仅有助于减少系统中的重复代码,还能降低模块之间的耦合性,从而提升系统的可扩展性和可维护性。

在 Spring 框架中,AOP 基于动态代理技术实现。如果被代理的对象实现了某个接口,Spring AOP 将使用 JDK Proxy 来创建代理对象。如果对象未实现接口,则 Spring AOP 会采用 Cglib 来生成一个被代理对象的子类以进行代理,如下图所示:

图片

AOP 相关的重要概念

AOP 涉及一些专业术语,这些术语的定义如下:

术语含义
目标(Target)被通知的对象
代理(Proxy)应用通知后的目标对象的代理
连接点(JoinPoint)目标对象所属类中定义的所有方法
切入点(Pointcut)被切面拦截或增强的连接点
通知(Advice)在连接点处执行的增强逻辑
切面(Aspect)切入点与通知的结合体
织入(Weaving)将通知应用到目标对象并生成代理的过程

Spring AOP 与 AspectJ 的区别

Spring AOP 是运行时增强,而 AspectJ 是编译时增强。 Spring AOP 主要依靠代理机制,而 AspectJ 则使用字节码操作。虽然 Spring AOP 已集成了 AspectJ,且 AspectJ 被视为 Java 生态系统中最全面的 AOP 框架,但相较之下,Spring AOP 更为简单易用。

在切面数量较少的情况下,Spring AOP 与 AspectJ 的性能差异不大。然而,当切面数量增多时,AspectJ 的性能优势会更加明显。

AspectJ 支持的通知类型

AspectJ 定义了多种通知类型,具体包括:

  • Before(前置通知):在目标对象的方法调用之前触发。
  • After(后置通知):在目标对象的方法调用之后触发。
  • AfterReturning(返回通知):在目标对象方法执行完毕且返回结果后触发。
  • AfterThrowing(异常通知):当目标对象的方法抛出异常时触发。请注意,AfterReturning 和 AfterThrowing 是互斥的。
  • Around(环绕通知):提供编程式控制目标对象方法的调用。环绕通知提供了最大的灵活性,因为它可以在方法调用前后进行操作,甚至可以选择不调用该方法。

如何控制多个切面的执行顺序?

  1. 通常情况下,可以使用 @Order 注解直接定义切面的执行顺序。
// 值越小,优先级越高  
@Order(3)  
@Component  
@Aspect  
public class LoggingAspect implements Ordered {  
  1. 另外,可以实现 Ordered 接口并重写 getOrder 方法。
@Component  
@Aspect  
public class LoggingAspect implements Ordered {  
    // ....  
    @Override  
    public int getOrder() {  
        // 返回值越小,优先级越高  
        return 1;  
    }  
}