Spring Boot 的 AOP

1. AOP

1. wiki

名词:

  • 通知(Advice): 包含了需要用于多个应用对象的横切行为,定义了“什么时候”和“做什么”。
  • 连接点(Join Point): 是程序执行过程中能够应用通知的所有点。
  • 切点(Poincut): 是定义了在“什么地方”进行切入,哪些连接点会得到通知。显然,切点一定是连接点。
  • 切面(Aspect): 是通知和切点的结合。通知和切点共同定义了切面的全部内容——是什么,何时,何地完成功能。
  • 引入(Introduction): 允许我们向现有的类中添加新方法或者属性。
  • 织入(Weaving): 是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。

创建:

  • 定义切面:在类上使用 @Component@Aspect 注解,表明该类不仅仅是一个POJO,还是一个切面容器
  • 定义切点:通过 @Pointcut 注解和切点表达式定义的
  • 定义通知:

2. 使用

1. 切点注解

@PointCut 切入点表达式包括一个 execution 表达式和 argNames。表达式有:

1. execution

execution([可见性]返回类型[声明类型].方法名(参数)[异常]),其中 [] 内的是可选的,其他的还支持通配符的使用,如 *、...、+、&&、||、!

1
2
@Pointcut("execution(* com.demo.service.*.*(..))")
public void pointCut() {}
2. within

用来指定类型,指定类型中的所有方法将被拦截。

1
2
// 匹配 UserServiceImpl 类对应对象的所有方法调用
@Pointcut("within(com.demo.service.UserServiceImpl)")
3. thistarget
  • this(TYPE): 代表代理对象,当目标对象被代理之后生成的代理对象和指定的类型匹配才会被拦截。
  • target(TYPE): 表示被代理的目标对象,当被代理的目标对象可以转换为指定的类型时则表示匹配。

不同点:

  1. this 作用于代理对象,target 作用于目标对象
  2. this 表示目标对象被代理之后生成的代理对象和指定的类型匹配会被拦截,匹配的是代理对象
  3. target 表示目标对象和指定的类型匹配会被拦截,匹配的是目标对象
    1
    2
    @Pointcut("this(com.demo.service.UserService)")
    @Pointcut("target(com.demo.service.UserService)")
4. args

用来匹配方法参数

1
@Pointcut("args(com.demo.service.UserService)")
5. @target@within
  • @target: 匹配的目标对象的类有一个指定的注解,被调用的目标对象中是否声明了指定注解,如果有,会被拦截
  • @within: 指定匹配必须包含某个注解的类里的所有连接点,被调用的方法所属的类中是否声明了指定注解,如果有,会被拦截
    1
    2
    @Pointcut("@target(com.demo.service.Annotation)")
    @Pointcut("@within(com.demo.service.Annotation)")
6. @annotation

匹配有指定注解的方法,注解作用在方法上面。

1
@Pointcut("@annotation(com.demo.service.Annotation)")
7. @args

方法参数所属的类型上有指定的注解,被匹配

2. 通知注解

  • @Before: 前置通知,在目标方法调用之前调用通知
  • @After: 后置通知,在目标方法完成之后调用通知
  • @Around: 环绕通知,在被通知的方法调用之前和调用之后执行自定义的方法
  • @AfterReturning: 返回通知,在目标方法成功执行之后调用通知
  • @AfterThrowing: 异常通知,在目标方法抛出异常之后调用通知

3. 其他地方调用

  • getAopProxy: 在 service 层调用本类中的 aop 切入方法时,是无法得到切入后的代理方法,可以使用该方法获取 AOP 代理后的类
    1
    2
    // 获取 AOP 代理后的类,并调用其方法
    AopContext.getAopProxy(this).selectRoleList(new SysRole());