2023-04-07-AOP

2023-04-07-AOP.md

Posted by lily on April 7, 2023

Spring AOP编程

1. 什么是面向切面编程(AOP)

  • AOP是一种编程思想,它将程序的业务逻辑和系统服务分离开来,通过对横切关注点的分离,它可以使得业务逻辑和系统服务更加清晰,降低了模块间的耦合度,提高了系统的可重用性,同时提高了开发的效率。

  • 在软件开发中,散布于应用中多处的功能被称为横切关注点(比如日志、安全和事务管理)。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑之中)。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题。

  • 简而言之,横切关注点可以被描述为影响应用多处的功能,AOP能帮助我们模块化横切关注点(切面)。在使用面向切面编程时,我们仍然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的业务逻辑类。

2. 面向切面编程的好处:

每个横切关注点都集中于一个地方,而不是分散到多处代码中。 服务模块更简洁,因为它们只包含业务逻辑的代码,而横切关注点的代码被转移到一个统一的地方了。

AOP术语

  1. 横切关注点 跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志、安全、缓存、事务等等。

  2. 连接点 连接点是在应用执行中能够插入切面的一个点。即程序执行过程中能够应用通知的所有点。

  3. 切点 切点是真正需要插入切面的一个或多个连接点。即通知被应用的具体位置。 通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点(比如Aspect切点表达式)。

  4. 通知 切面的工作被称为通知。通知是在特定的连接点上执行的,它是一种在程序执行期间插入切面的方法。通知的类型有:前置通知、后置通知、异常通知、最终通知、环绕通知。

  5. 切面
  6. 织入
  7. 引用

    通知的类型

    • 前置通知(Before):在目标方法被调用之前调用通知功能。
    • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
    • 返回通知(After-returning):在目标方法成功执行之后调用通知。
    • 异常通知(After-throwing):在目标方法抛出异常后调用通知。
    • 环绕通知(Around) :通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

3. Spring AOP的实现

这是一个具体通知类的实现,它包含了一个通知方法,该方法将在切点执行时被调用。

    @Aspect
public class Audience {
    // performance()方法的实际内容并不重要,它只是一个标识,供@Pointcut注解依附
    @Pointcut("execution(* concert.Performance.perform(..))")  // 定义命名的切点
    public void performance() {

    }

    @Before("performance()")     // 前置通知
    public void silenceCellPhones() {
        System.out.println("Silencing cell phones");
    }

    @Before("performance()")     // 前置通知
    public void takeSeats() {
        System.out.println("Taking seats");
    }

    @AfterReturning("performance()")     // 返回通知
    public void applause() {
        System.out.println("CLAP CLAP CLAP!!!");
    }

    @AfterThrowing("performance()")      // 异常通知
    public void demandRefund() {
        System.out.println("Demanding a refund");
    }
}

环绕通知

    @Around("performance()")
    public Object watchPerformance(ProceedingJoinPoint jp) {
        try {
            System.out.println("Silencing cell phones");
            System.out.println("Taking seats");
            jp.proceed();
            System.out.println("CLAP CLAP CLAP!!!");
        } catch (Throwable e) {
            System.out.println("Demanding a refund");
        }
        return null;
    }