AOP

面向切面编程,及不侵入业务代码的情况下,实现功能的增强

底层

动态代理(cglib)

术语

连接点

哪些方法可以被增强,则那些方法被称为连接点

切入点

实际真正被增强的方法,被称为切入点

通知(增强)

实际增强的逻辑部分,叫做通知

通知的类型

  1. 前置通知
    1. 在被增强的方法前面执行
  2. 后置通知
    1. 在被增强的方法后面执行
  3. 环绕通知
    1. 在被增强方法执行前后均执行
  4. 异常通知
    1. 方法抛出异常时执行
  5. 最终通知
    1. 被增强方法执行完毕后执行

切面

是一个动作,把通知应用到切入点的过程

AOP 操作

AspectJ 框架

什么是 AspectJ

是一个单独的框架,不是 spring 的组成部分

基于 AspectJ 实现 Aop 操作

  1. xml 方式
  2. 注解方式(常用)

依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

切入点表达式

作用

直到对哪个类里面的方法进行增强

语法

execution([权限修饰符][返回类型(可省略)][全限定类名][方法名称][参数列表])

举例

  1. 对类中某方法进行增强
execution(* springdemo.dao.add(..))
  1. 对类中所有方法进行增强
execution(* springdemo.dao.*(..))
  1. 对包中所有类的所有方法进行增强
execution(* springdemo.*.*(..))

AOP 注解操作

创建被增强类

package AOP;

import org.springframework.stereotype.Component;

@Component
public class User {
    public void add(){
        System.out.println("add...");
    }
    public void update(){
        System.out.println("update....");
    }
}

创建增强类

package AOP;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Enhance {
    @Before(value = "execution(* AOP.User.add(..))")
    public void before(){
        System.out.println("前置通知执行");
    }
    @After(value = "execution(* AOP.User.add(..))")
    public void after(){
        System.out.println("后置通知执行");
    }
    @AfterReturning(value ="execution(* AOP.User.add(..))" )
    public void afterReturn(){
        System.out.println("最终通知执行");
    }
    @Around(value = "execution(* AOP.User.add(..))")
    public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("执行环绕通知(被增强方法之前)");
        proceedingJoinPoint.proceed();
        System.out.println("执行环绕通知(被增强方法执行后)");
    }
    @AfterThrowing(value = "execution(* AOP.User.add(..))")
    public void AfterT(){
        System.out.println("执行异常通知");
    }
}

进行通知的配置

开启组件扫描

开启 AOP

<context:component-scan base-package="AOP"></context:component-scan>
 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

执行

执行环绕通知(被增强方法之前)
前置通知执行
add...
执行环绕通知(被增强方法执行后)
后置通知执行
最终通知执行

公共切入点抽取

@PointCut 做抽取

调用被@PointCut 修饰的方法

image.png

两个代理类对同一个方法做增强,其执行顺序

在代理类上加@Order 注解(value 是一个数字,越小,优先级越高)