AOP 深入理解与使用方法

底层实现:通过动态代理实现

AOP核心概念

相关注解

类注解:

        @Component    表示将该类交给IOC容器管理

        @Aspect   表示这是个切面类

方法注解:

        通过切入点表达式指定面向哪些连接点编程,即该方法的作用范围

        例:@Around(“execution(*tlias.service.impl.DeptServiceImpl.*(..))”)

        注:切入点表达式具体写法再后面会讲到

AOP执行流程:

       原理:代码执行中需要注入这个对象,而这个对象中的方法是被AOP标记了的。所以在注入对象时,会根据原始对象生成一个代理对象(代理对象中的方法就是通过AOP增强后的方法)。再调用注入的对象的方法时,执行的就是代理对象的方法,也就执行了我们AOP需要增强的代码逻辑。所以AOP增强代码逻辑实现的前提是,代码运行时需要注入一个该对象,并且在后续调用了该对象被AOP增强的那个方法。

        代码实际执行流程:在执行该方法时,由于调用该方法的对象是注入的是代理对象,而代理对象的方法是经过AOP增强的方法,所以代理对象的方法中中包含我们再方法运行前要执行的代码逻辑,原本的方法逻辑,以及我们再方法运行后要执行的代码逻辑,按照这个顺序依次执行。

解决我之前存在的一些困惑:

          实际执行中,应该就是直接调用这个代理对象的方法,代理对象的方法包含了所有的代码逻辑。

          但是我们在断点测试时,由于看不见这个代理对象(因为创建对象就需要对应的实体类,但是我们本身没有创建这个实体类,而是通过动态代理创建的对象)。所以我们测试时,代码只能通过在AOP方法和原始方法间来回跳转来执行代码:先跳转到AOP方法执行运行前逻辑,再跳转到对象类执行方法,再跳回AOP方法执行运行后逻辑。

        但这并不表示实际上执行的是AOP中的方法,和原始对象类中的方法,实际上执行的则是代理对象中增强后的方法。

 通知类型       

@before @After @AfterReturning @AfterThrowing

方法返回值均为void,加上注解以后,直接在方法体中书写要执行的逻辑即可。这些逻辑在实际运行时就会在方法前或后执行,具体的执行顺序参照上图即可。

@Around

        参数列表为什么有一个ProceedingJoinPoint : 由于@Around通知,既包含了方法执行前通知,方法执行后通知,所以得对前后进行区分,所以该方法的参数列表里有一个ProceedingJoinPoint对象,通过这个对象我们可以调用原始方法执行,以此来区分该方法执行前后需要执行的代码逻辑。

        返回对象为什么是Object :由于调用的原始方法可能是存在返回值的,我们也需要把原始方法的返回值传递出去,不影响代码的正常运行。

存在的疑问:

        为什么除去@Around需要我们手动返回原始对象的返回值,而其他通知类型不需要返回原始方法的返回值呢,那些原始方法的返回值也可能不为null呀。

猜测:

        可能是因为除@Around外的通知类型,代码执行流程简单(只需要在代码运行前或者代码运行后执行即可),所以底层已经自动帮我们返回了原始方法的返回值,所以不需要我们手动返回原始方法的返回值了。

查找资料得出的结果:

为什么 @Around 需要手动返回原始方法的返回值

  1. 控制权

    • @Around 通知提供了最大的灵活性,因为它允许你完全控制目标方法的调用过程。
    • 在 @Around 通知中,你可以决定何时调用目标方法、如何调用以及如何处理返回值。
    • 这种灵活性要求你在通知中显式地调用 proceedingJoinPoint.proceed() 方法来执行目标方法,并且需要显式地处理和返回目标方法的返回值。
  2. 动态行为

    • @Around 通知可以用来实现动态代理,例如,可以有条件地调用目标方法或返回不同的结果。
    • 这种动态行为需要开发者显式地控制方法的执行流程。

@Before@After@AfterReturning 、 @AfterThrowin g这些通知类型,它们都是通过动态代理机制实现的。这些通知类型的设计目的是在目标方法调用前后执行某些逻辑,而不干扰目标方法本身的执行流程。因此,Spring AOP 代理对象会自动处理目标方法的调用,并将结果返回给调用方。Spring AOP 代理对象会自动处理目标方法的调用和返回值,因此这些通知类型不需要显式返回目标方法的返回值。而 @Around 通知则提供了更大的灵活性,需要显式地调用目标方法并返回结果。

通知的执行顺序

情景:当有多个切面的切入点匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。

切入点表达式

@execution切入点表达式   

语法

通配符号

书写建议

常用标签:@Pointcut

使用场景:切入点表达式需要多次重复书写时,可以使用@Pointcut注解声明一个方法

使用方法:在需要用到该切入点表达式时,直接在通知类型的注解上调用该方法即可

使用试例:

注意: 1.切入点表达式的方法权限修饰符为private则只能在本类中访问该方法。

            2.在需要输入切入点表达式的地方,IDEA会自动提示该方法。

                    

@annotation切入点表达式

介绍:用于匹配标识有特定注解的方法

例:

使用方法:(也可以通过@pointcut注解来使用)

        1.自定义一个注解

        2.在@annotation注解中指定包名类名等,最后指定需要匹配的注解

        3.在需要指定的方法上加该注解即可

按顺序依次举例如下

优势: 可以更灵活的匹配需要的方法

缺点:需要自己依次在对应方法上加自定义的注解

连接点

介绍

理解:子类型在继承父类方法的基础上还可以增加一些特有方法,所以@Around通知要比其他通知类型获取的相关信息多。

接入点信息获取 试例代码:

@around

其他通知类型

各通知类型可获取的接入点信息

1. @Before 通知

作用:在目标方法调用之前执行。

连接点信息

  • 签名(Signature):获取目标方法的签名信息,包括方法名、参数类型等。
  • 参数(Arguments):获取目标方法的传入参数。

2.@After 通知

作用:在目标方法执行之后执行,无论方法是否抛出异常。

连接点信息

  • 签名(Signature):获取目标方法的签名信息。
  • 参数(Arguments):获取目标方法的传入参数。
  • 目标对象(Target):获取被代理的目标对象。
  • 代理对象(This):获取当前执行通知的代理对象。

3. @AfterReturning 通知

作用:在目标方法成功返回后执行。

连接点信息

  • 签名(Signature):获取目标方法的签名信息。
  • 参数(Arguments):获取目标方法的传入参数。
  • 目标对象(Target):获取被代理的目标对象。
  • 代理对象(This):获取当前执行通知的代理对象。
  • 返回值(Return Value):获取目标方法的返回值。

4. @AfterThrowing 通知

作用:在目标方法抛出异常后执行。

连接点信息

  • 签名(Signature):获取目标方法的签名信息。
  • 参数(Arguments):获取目标方法的传入参数。
  • 目标对象(Target):获取被代理的目标对象。
  • 代理对象(This):获取当前执行通知的代理对象。
  • 异常对象(Thrown Exception):获取目标方法抛出的异常对象。

在 Spring AOP 中,@Around 通知是最强大的通知类型之一,因为它允许你完全控制目标方法的调用过程。@Around 通知提供了对连接点(JoinPoint)的全面访问,并且允许你在方法调用前后执行自定义逻辑。以下是 @Around 通知可以获取的连接点信息:

5.@Around 通知

  1. 签名(Signature)

    • JoinPoint 的 getSignature() 方法可以获取目标方法的签名信息。
    • 这包括方法名、参数类型等。
  2. 方法参数(Arguments)

    • JoinPoint 的 getArgs() 方法可以获取目标方法的传入参数。
  3. 目标对象(Target)

    • JoinPoint 的 getTarget() 方法可以获取被代理的目标对象。
    • 这是原始的目标对象,即你实际想要代理的对象。
  4. 代理对象(This)

    • JoinPoint 的 getThis() 方法可以获取当前执行通知的代理对象。
    • 这是经过 Spring AOP 代理后的对象。
  5. 返回值(Return Value)

    • 在 @Around 通知中,你需要显式地调用 ProceedingJoinPoint.proceed() 方法来执行目标方法,并且可以获取其返回值。
    • 你可以选择是否继续执行目标方法,或者直接返回一个自定义的结果。
  6. 异常(Thrown Exception)

    • 如果目标方法抛出了异常,你可以捕获该异常并进行处理。

使用场景

1. 日志记录

应用场景:在系统中记录方法的调用时间和执行结果,对于调试和运维非常重要。

2. 性能监控

应用场景:记录方法执行的时间,帮助优化性能瓶颈。

3. 安全性和认证

应用场景:确保只有授权的用户才能访问特定的方法或资源。

4. 事务管理

应用场景:确保业务逻辑中的方法在执行过程中遵循事务一致性原则。

5. 缓存

应用场景:缓存方法的结果,减少不必要的重复计算。

6. 异常处理

应用场景:统一处理方法中抛出的异常,并记录日志或进行其他操作。

7. 通知和事件发布

应用场景:在方法执行前后发送通知或发布事件。

总结

面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它允许将横切关注点(cross-cutting concerns)从业务逻辑中分离出来,从而提高代码的模块化程度。在实际开发中,AOP 有许多典型的应用场景,可以简化开发工作并提高代码的可维护性,帮助你更好地组织和管理代码。通过使用 AOP,你可以将横切关注点从业务逻辑中分离出来,提高代码的可读性和可维护性。

完结

         如有错误,欢迎指正。

  • 26
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值