Spring AOP 编程增强

切面通知应用增强

通知类型

在基于Spring AOP编程的过程中,基于AspectJ框架标准,spring中定义了五种类型的通知(通知-Advice描述的是一种扩展业务),它们分别是:

  • @Before。

  • @AfterReturning。目标方法执行结束没有出现异常时

  • @AfterThrowing。目标方法出现异常执行结束时

  • @After。不管目标方法有没有出现异常,只要目标方法结束

  • @Around.重点掌握(优先级最高)

  说明:在切面类中使用什么通知,由业务决定,并不是说,在切面中要把所有通知都写上。

假如说我们现在有一种业务,这种业务要以某一种方式织入到我们原有的对象上去。那我们可以通过通知,去把那个业务封装起来,然后由代理对象去调用我们切面的通知方法,来为目标方法做功能扩展。而这种方式恰巧是oop的一种补充。

通知执行顺序

假如这些通知全部写到一个切面对象中,其执行顺序及过程,如图所示(但是这个顺序现在在springboot工程的不同版本中可能会有一些不同,在2.3.0之前是下面这张图,如果项目上有严谨的顺序要求时,建议使用@Around):

说明:实际项目中可能不会在切面中定义所有的通知,具体定义哪些通知要结合业务进行实现。

通知实践过程分析

这里的测试可以用我们之前写的项目进行测试(看我的基础及原理那篇)

代码如下

package com.cy.pj.common.aspect;

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

@Component
@Aspect
public class SysTimeAspect {
    @Pointcut("bean(mailServiceImpl)")
    public void doTime(){}

    @Before("doTime()")
    public void doBefore(){
        System.out.println("time doBefore()");
    }
    @After("doTime()")
    public void doAfter(){
        System.out.println("time doAfter()");
    }
    /**核心业务正常结束时执行* 说明:假如有after,先执行after,再执行returning*/
    @AfterReturning("doTime()")
    public void doAfterReturning(){
        System.out.println("time doAfterReturning");
    }
    /**核心业务出现异常时执行说明:假如有after,先执行after,再执行Throwing*/
    @AfterThrowing("doTime()")
    public void doAfterThrowing(){
        System.out.println("time doAfterThrowing");
    }
    @Around("doTime()")
    public Object doAround(ProceedingJoinPoint jp)
            throws Throwable{
        System.out.println("doAround.before");
        try{
            Object obj=jp.proceed();
            System.out.println("doAround.after");
            return obj;
        }catch(Throwable e){
            System.out.println(e.getMessage());
            throw e;
        }

    }
}

然后进行测试,得到的结果如下

我们发现,AfterReturning和After和我之前那张图,顺序不一样。这就是因为版本的问题。刚才我们测得是springboot2.3.4版本。

说明:对于@AfterThrowing通知只有在出现异常时才会执行,所以当做一些异常监控时可在此方法中进行代码实现。

切入点表达式增强

Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义及说明:

bean表达式(重点)

bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:

(1)bean("userServiceImpl")指定一个userServiceImpl类中所有方法。

(2)bean("*ServiceImpl")指定所有后缀为ServiceImpl的类中所有方法。

说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的名字应该是spring容器中某个bean的name。

within表达式(了解)

within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:

(1)within("aop.service.UserServiceImpl")指定当前包中这个类内部的所有方法。 

(2)within("aop.service.*") 指定当前目录下的所有类的所有方法。

(3)within("aop.service..*") 指定当前目录以及子目录中类的所有方法。

within表达式应用场景分析:

(1)对所有业务bean都要进行功能增强,但是bean名字又没有规则。

(2)按业务模块(不同包下的业务)对bean对象进行业务功能增强。

execution表达式(了解)

execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析:

语法:execution(返回值类型 包名.类名.方法名(参数列表))。

(1)execution(void aop.service.UserServiceImpl.addUser())匹配addUser方法。

(2)execution(void aop.service.PersonServiceImpl.addUser(String)) 方法参数必须为String的addUser方法。

(3)execution(* aop.service..*.*(..)) 万能配置。aop.service包及子包下所有类中的所有方法

@annotation表达式(重点)

@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析

@annotation(anno.RequiredLog) 匹配有此注解描述的方法。

@annotation(anno.RequiredCache) 匹配有此注解描述的方法。

其中:RequiredLog为我们自己定义的注解,当我们使用@RequiredLog注解修饰业务层方法时,系统底层会在执行此方法时进行日扩展操作。

推荐细粒度的切入点表达式使用@annotation表达式,更加灵活。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值