AOP进阶一(通知类型,重复切入点表达式的提取,通知顺序)

1.通知类型

前面我们介绍了这是环绕通知@Around--此注解标注的通知方法在目标方法前后都被执行,还有

前置通知@Before--此注解标注的通知方法在目标方法前都被执行,

后置通知@After--此注解标注的通知方法在目标方法前都被执行,无论是否有异常都会执行

返回后通知@AfterReturning--此注解标注的通知方法在目标方法前都被执行,有异常不会执行

异常后通知@AfterThrowing--此注解标注的通知方法在发生异常后执行

通知类型就是定义重复代码的位置是在哪里,重点区分后三个。

@Slf4j
@Component
@Aspect
public class MyAspect1 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        log.info("before ...");
    }

    //环绕通知
    @Around("execution(* com.itheima.service.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");
        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();
        //原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了
        log.info("around after ...");
        return result;
    }

    //后置通知
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(JoinPoint joinPoint){
        log.info("after ...");
    }

    //返回后通知(程序在正常执行的情况下,会执行的后置通知)
    @AfterReturning("execution(* com.itheima.service.*.*(..))")
    public void afterReturning(JoinPoint joinPoint){
        log.info("afterReturning ...");
    }

    //异常通知(程序在出现异常的情况下,执行的后置通知)
    @AfterThrowing("execution(* com.itheima.service.*.*(..))")
    public void afterThrowing(JoinPoint joinPoint){
        log.info("afterThrowing ...");
    }
}

注:

1.Around是环绕在方法帮的,所以里面目标方法前面的代码比前置通知后执行,目标方法后面的代码比后置通知早执行。

2.环绕通知中原始方法调用是有异常,通知中环绕后的代码逻辑额不会执行

3.环绕通知方法的返回值,必须指定为Object,来接受原始方法的返回值,否则原始方法执行完毕,是获取不到返回值的。


2.重复切入点表达式的抽取

很多情况下切入点表达式是重复的。

Spring提供了@PointCut注解,该注解的作用是将公共的切入点表达式抽取出来,需要的时候引用改切入点表达式即可。

例子:

原来:

//前置通知
@Before("execution(* com.itheima.service.*.*(..))")
//环绕通知
@Around("execution(* com.itheima.service.*.*(..))")
//后置通知
@After("execution(* com.itheima.service.*.*(..))")
//返回后通知(程序在正常执行的情况下,会执行的后置通知)
@AfterReturning("execution(* com.itheima.service.*.*(..))")
//异常通知(程序在出现异常的情况下,执行的后置通知)
@AfterThrowing("execution(* com.itheima.service.*.*(..))")

使用@PointCut注解提取后:

@Slf4j
@Component
@Aspect
public class MyAspect1 {
    //切入点方法(公共的切入点表达式)
    @Pointcut("execution(* com.itheima.service.*.*(..))")
    private void pt(){

    }



    //前置通知(引用切入点)
    @Before("pt()")
    public void before(JoinPoint joinPoint){
    }
    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    }
    //后置通知
    @After("pt()")
    public void after(JoinPoint joinPoint){
    }
    //返回后通知
    @AfterReturning("pt()")
    public void afterReturning(JoinPoint joinPoint){
    }
    //异常通知
    @AfterThrowing("pt()")
    public void afterThrowing(JoinPoint joinPoint){
    }
}

注:当外部其他切面类中也要引用当前类中的切入点表达式,就需要吧private改为public,而在引用的时候,具体的语法为:全类名.方法名,具体形式如下:

@Slf4j
@Component
@Aspect
public class MyAspect2 {
    //引用MyAspect1切面类中的切入点表达式
    @Before("com.itheima.aspect.MyAspect1.pt()")
    public void before(){
        log.info("MyAspect2 -> before ...");
    }
}

3.通知顺序

当在项目开发当中,我们定义了多个切面类,而多个切面类中多个切入点都匹配到了同一个目标方法,目标方法在运行的时候,这多个切面类地址的这些通知方法都会执行。

不同切面类中,默认按照切面类的类名字母排序:

目标方法前的通知方法:字母排名靠前的先执行

目标方法后的通知方法:字母排名靠前的后执行

如果我们想控制通知的执行顺序有两种方式:

1.修改切面类的类名(一般不会这样做)

2.使用Spring提供的order注解。

例:

@Slf4j
@Component
@Aspect
@Order(2)  //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
public class MyAspect2 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(){
        log.info("MyAspect2 -> before ...");
    }

    //后置通知 
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(){
        log.info("MyAspect2 -> after ...");
    }
}

@Slf4j
@Component
@Aspect
@Order(3)  //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
public class MyAspect3 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(){
        log.info("MyAspect3 -> before ...");
    }

    //后置通知
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(){
        log.info("MyAspect3 ->  after ...");
    }
}

@Slf4j
@Component
@Aspect
@Order(1) //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
public class MyAspect4 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(){
        log.info("MyAspect4 -> before ...");
    }

    //后置通知
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(){
        log.info("MyAspect4 -> after ...");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值