彻底熟练玩转Spring AOP(Pointcut,Advice,Joinpoint)

AOP的本质就是运用了动态代理
  两种动态代理的方式:CGlib和JDK原生动态代理(两种区别在别的文章有记录)
 

  强制全部使用CGLIB动态代理的两种方式

spring.aop.proxy-target-class=true

@EnableAspectJAutoProxy(proxyTargetClass = true)

本篇主要记录AOP的具体运用


①定义切点

  切点表达式(盗图)

  表达式由六部分组成:

表达式主体 (方法访问权限(可省略) 返回类型 包路径 类名 方法参数类型)

  其中表达式主体有以下这些:

 

举几个例子:
  com.yuwenwen.controller包下的所有类的所有方法,所有方法参数,所有返回类型,都作为切点

 @Pointcut("execution(* com.yuwenwen.controller.*.*(..))")

  com.yuwenwen.controller包或者子包下的所有类的所有方法,所有方法参数,所有返回类型,都作为切点

 @Pointcut("execution(* com.yuwenwen.controller..*.*(..))")

  com.yuwenwen.controller包下的YuwenwenAop类的所有方法,所有方法参数,所有返回类型,都作为切点

 @Pointcut("execution(* com.yuwenwen.controller.YuwenwenAop.*(..))")

  任何包下的所有类的send所有方法参数,都作为切点

 @Pointcut("execution(* *.send(..))")

 对AnthCheck注解作为切点

@Pointcut("@annotation(com.syan.cloudbiz2.aop.AnthCheck)")

 

②通知

前置通知 Before:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常
后置通知 After returning:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行
异常通知 After throwing:在连接点抛出异常后执行
最终通知 After:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容
环绕通知 Around:环绕通知围绕在连接点前后,能在方法调用前后自定义一些操作,还需要负责决定是继续处理 join point (调用 ProceedingJoinPoint 的 proceed 方法)还是中断执行

  可能很多人看到有这种写法,把切点给单提出来一个方法,也有不提出来方法的,其实他俩的效果是一样的,只不过可能有多种通知都对这一个切点进行操作时,提出来一个方法比较方便

    @Pointcut("execution(* com.yuwenwen.controller.*.send(..))")
    public void point() {
    }

    @After("point()")
    public void after() {
        System.out.println("after advice");
    }

    @After("execution(* com.yuwenwen.controller.*.send(..))")
    public void after() {
        System.out.println("after advice");
    }

通知的执行顺序

这块@Before@After不做详细说明,就是一个在执行方法前,一个在执行方法后。

重点说一下@Around(环绕)这种通知:

  @Around的定义的方法参数必须得有ProceedingJoinPoint

    @Around("point()")
    public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("@Around:执行目标方法之前...");
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("@Around:执行目标方法之后...");
        return obj
}

  以proceedingJoinPoint.proceed()为界限
  以上的逻辑就是在before之前执行的逻辑
  以下就是执行真正方法后到after之前的逻辑
@AfterThrowing
  如果目标方法抛出异常,会走around下部分逻辑,和after逻辑之后才会走afterThrowing的逻辑,而不是抛异常之后直接就走afterThrowing的逻辑

  可以对抛出来的异常进行再次封装

    @AfterThrowing(value = "point()", throwing = "ex")
    public void AfterThrowing(Throwable ex) {
        if (ex instanceof RuntimeException) {
            throw new RuntimeException();
        }
        System.out.println("异常通知....");
    }

③Joinpoint


Joinpoint在做切面的逻辑的时候是一个很重要的参数
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象
Joinpoint常用方法如下:

方法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs();获取传入目标方法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象

    @Before("point()")
    public void Before(JoinPoint joinPoint) {
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String proxy = joinPoint.getThis().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println(
            "@before Execute! --class name: " + classname + ", method name: " + methodName + ", proxy name: "
                + proxy + " " + args);
    }

 打印结果:

@before Execute! --class name: OrderController, method name: send, proxy name: OrderController$$EnhancerBySpringCGLIB$$40fe67e4 [com.sbi.dto.DoIn@6c8ea82a]

问:getTarget和getThis的区别
AOP的本质就是生成代理类放到Spring容器去.
举例说明,对OrderController做AOP,其本质是生成了一个代理类(OrderControllerProxy)放入Spring容器里面,这样就会出现代理对象和被代理对象
getTarget则是OrderController
getThis就是为这个代理对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值