AOP的各种通知

AOP的各种通知

在使用Spring的AOP特性中,Spring为我们提供了多种通知注解,方便我们灵活地用各种方式做切入

首先我们定义一个用于简单除法运算的主业务类和主业务方法,来方便我们演示各种通知方法的切入效果

public class MyCalculator {

    public int calculate(int a, int b) {
        int result = a / b;
        System.out.println("切入点方式执行,结果为" + result);
        return result;
    }
}

前置通知

前置通知的作用是将通知方法的逻辑切入到切入点方法之前,使用的时候将@Before注解添加到通知方法上,并在注解的属性中指定切入点方法即可

@Aspect
public class LogAspects {

    @Before("execution(public int com.blackball.component.MyCalculator.calculate(int,int))")
    public void beforeLog() {
        System.out.println("执行前置通知");
    }
}

执行结果如下

在这里插入图片描述

后置通知

后置通知的作用是将通知方法的逻辑切入到切入点方法之后,使用@After注解,使用的方法和前置通知一样

@Aspect
public class LogAspects {

    @After("execution(public int com.blackball.component.MyCalculator.calculate(int,int))")
    public void afterLog() {
        System.out.println("执行后置通知");
    }
}

执行结果如下

在这里插入图片描述

返回通知

返回通知的作用是得到方法的返回值,然后在方法结束后执行通知方法,使用@AfterReturning注解,在通知方法的参数列表添加一个参数作为通知获取的返回值,并在注解的returning属性指定这个参数

@Aspect
public class LogAspects {

    @AfterReturning(pointcut = "execution(public int com.blackball.component.MyCalculator.calculate(int,int))", returning = "result")
    public void returnLog(int result) {
        System.out.println("执行返回通知,返回结果为" + result);
    }
}

执行结果如下

在这里插入图片描述

异常通知

异常通知的作用是在切入点方法出现异常时,获取该异常,然后执行通知方法进行处理,使用@AfterThrowing注解,使用方法和返回通知相似,在通知方法的参数列表添加一个异常作为通知获取的异常,并在注解的throwing属性指定这个异常

@Aspect
public class LogAspects {

    @AfterThrowing(pointcut = "execution(public int com.blackball.component.MyCalculator.calculate(int,int))", throwing = "exception")
    public void exceptionLog(Exception exception) {
        System.out.println("执行异常通知,异常为" + exception);
    }
}

我们在测试代码中调用主业务方法,并且制造一个除0异常

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    MyCalculator calculator;

    @Test
    void contextLoads() {
        calculator.calculate(10, 0);
    }

}

执行结果如下

在这里插入图片描述

环绕通知

环绕通知的作用是在通知内部,手动地调用切入点方法,自定义切入点方法执行的时机,可以在切入点方法执行的前后都添加增强逻辑,使用@Around,在通知方法的参数列表添加一个 ProceedingJoinPoint对象参数作为切入点方法对象,在通知方法中,调用ProceedingJoinPoint对象的proceed方法,执行切入点方法,注意环绕通知的返回类型需要与切入点方法匹配

@Aspect
public class LogAspects {

    @Around("execution(public int com.blackball.component.MyCalculator.calculate(int,int))")
    public int aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行环绕通知之前");
        int result = (int) joinPoint.proceed();
        System.out.println("执行环绕通知之后,结果为" + result);
        return result;
    }
}

执行结果如下

在这里插入图片描述

获取切入点方法的信息

有时候我们需要在通知方法中获取切入点方法的信息进行处理,可以使用JoinPoint接口,在通知方法的参数类别中添加一个JoinPoint对象,使用JoinPoint对象可以获取切入点方法的信息

@Aspect
public class LogAspects {

    @Before("execution(public int com.blackball.component.MyCalculator.calculate(int,int))")
    public void beforeLog(JoinPoint joinPoint) {
        System.out.println(Arrays.toString(joinPoint.getArgs()));
        System.out.println(joinPoint.getSignature());
    }
}

执行结果如下

在这里插入图片描述

需要注意的是,当通知方法的参数列表有多个参数时,如使用返回通知或异常通知时,JoinPoint对象参数需要在参数列表的第一个位置才能生效

通知的执行顺序

现在我们将以上的通知方法都添加到切面类中一起生效,并测试他们的执行顺序

@Aspect
public class LogAspects {

    @Pointcut("execution(public int com.blackball.component.MyCalculator.calculate(int,int))")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void beforeLog() {
        System.out.println("执行前置通知");
    }

    @After("pointCut()")
    public void afterLog() {
        System.out.println("执行后置通知");
    }

    @AfterReturning(pointcut = "pointCut()", returning = "result")
    public void returnLog(int result) {
        System.out.println("执行返回通知,返回结果为" + result);
    }

    @AfterThrowing(pointcut = "pointCut()", throwing = "exception")
    public void exceptionLog(Exception exception) {
        System.out.println("执行异常通知,异常为" + exception);
    }

    @Around("pointCut()")
    public int aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行环绕通知之前");
        int result = (int) joinPoint.proceed();
        System.out.println("执行环绕通知之后");
        return result;
    }
}

正常情况

正常情况下的执行结果如下

在这里插入图片描述

可以看到正常情况下通知的执行顺序是:

  1. 环绕通知(前)
  2. 前置通知
  3. 切入点方法
  4. 返回通知
  5. 后置通知
  6. 环绕通知(后)

异常情况

异常情况下的执行结果如下

在这里插入图片描述

可以看到异常情况下通知的执行顺序是:

  1. 环绕通知(前)
  2. 前置通知
  3. 切入点方法(发生异常前部分)
  4. 异常通知
  5. 后置通知

注意以上执行顺序的测试结果基于Spring 5,Spring 4的测试结果会有所不同

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值