SpringBoot核心框架之AOP详解

SpringBoot核心框架之AOP详解

一、AOP基础

1.1 AOP概述
  • AOP:Aspect Oriented Programming(面向切面编程,面向方面编程),其实就是面向特定方法编程。
    • 场景:项目部分功能运行较慢,定位执行耗时较长的业务方法,此时就需要统计每一个业务的执行耗时。
    • 思路:给每个方法在开始前写一个开始计时的逻辑,在方法结束后写一个计时结束的逻辑,然后相减得到运行时间。

思路是没问题的,但是有个问题,一个项目是有很多方法的,如果挨个增加逻辑代码,会相当繁琐,造成代码的臃肿,所以可以使用AOP编程,将计时提出成一个这样的模板:

  1. 获取方法运行开始时间
  2. 运行原始方法
  3. 获取方法运行结束时间,计算执行耗时

原始方法就是我们需要计算时间的方法,并且可以对原始方法进行增强,其实这个技术就是用到了我们在Java基础部分学习的动态代理技术

实现:动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要是通过底层的动态代理机制,对特点的方法进行编程。

1.2 AOP快速入门

统计各个业务层方法执行耗时

  1. 导入依赖:在pom.xml中导入AOP的依赖。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 编写AOP程序:针对于特定方法根据业务需要进行编程。
@Slf4j // 日志
@Component // 将当前类交给spring管理
@Aspect // 声明这是一个AOP类
public class TimeAspect {
   
   

   @Around("execution(* com.example.service.*.*(..))")
   // @Around:表示这是一个环绕通知。
   // "execution(* com.example.service.*.*(..))":切入点表达式,它定义了哪些方法会被这个环绕通知所拦截。这个后面会详细讲解。
   // execution(* ...):表示拦截执行的方法。
   // * com.example.service.*.*(..):表示拦截 com.example.service 包下所有类的所有方法(* 表示任意字符的通配符)。
   // ..:表示方法可以有任意数量和类型的参数。
   public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
   
   
       // ProceedingJoinPoint是 Spring AOP 中的一个接口,在使用环绕通知时需要
       // 它继承自 JoinPoint 接口,并添加了 proceed() 方法。
       // 这个方法是 AOP 代理链执行的关键部分,它允许你在切面中执行自定义逻辑后继续执行原始方法。

       // 1. 记录开始时间
       long start = System.currentTimeMillis();

       // 2. 调用原始方法
       Object result = joinPoint.proceed(); // 执行被通知的方法。如果不调用 proceed(),被通知的方法将不会执行。

       // 3. 记录结束时间,计算耗时
       long end = System.currentTimeMillis();

       // getSignature():返回当前连接点的签名。
       log.info(joinPoint.getSignature()+"方法执行耗时:{}ms",end - start);

       return result;
   }
}
  1. 查看结果在这里插入图片描述

这样我们就完成了,一个AOP的小例子,但是AOP的功能远不能这些,他还有更多的实用的功能。比如:记录操作日志:可以记录谁什么时间操作了什么方法,传了什么参数,返回值是什么都可以很方便的实现。还有比如权限控制,事务管理等等。

我们来总结一下AOP的优势

  1. 代码无侵入
  2. 减少重复代码
  3. 提高开发效率
  4. 维护方便
1.3. AOP核心概念

连接点:JoinPoint,可以被连接点控制的方法(暗含方法执行时的信息)。 在此例中就是需要被计算耗时的业务方法。
通知:Advice,指那些重复的逻辑,也就是共性功能(最终体现为一个方法)。在此例中就是计算耗时的逻辑代码。
切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用。在此例中就是com.example.service 包下所有类的所有方法。
切面:Aspect,描述通知与切入点的对应关系(通知+切入点)。在此例中就是TimeAspect方法。
目标对象:Target,通知所应用的对象。在此例中就是通知com.example.service 包下所有类的所有方法。

1.4. AOP的执行流程

因为SpringAOP是基于动态代理实现的,所有在方法运行时就会先为目标对象基于动态代理生成一个代理对象,为什么说AOP可以增强方法,就是因为有一个代理方法,然后在AOP执行时,Spring就会将通知添加到代理对象的方法前面,也就是记录开始时间的那个逻辑代码,然后调用原始方法,也就是需要计时的那个方法,此时代理对象已经把原始方法添加到代理对象里面了,然后执行调用原始方法下面的代码,在此例中就是计算耗时的那部分,AOP会把这部分代码添加到代理对象的执行方法的下面,这样代理对象就完成了对目标方法的增强,也就是添加了计时功能,最后在程序运行时自动注入的也就不是原来的对象,而是代理对象了,不过这些都是AOP自动完成,我们只需要编写AOP代码即可。

二、AOP进阶

2.1. AOP支持的通知类型

通知类型:

  1. 环绕通知(Around Advice) 重点!!!:
  • 使用 @Around 注解来定义。
  • 包围目标方法的执行,可以在方法执行前后执行自定义逻辑,并且可以控制目标方法的执行。
  • 通过 ProceedingJoinPoint 参数的 proceed() 方法来决定是否执行目标方法。
  1. 前置通知(Before Advice)
  • 使用 @Before 注解来定义。
  • 在目标方法执行之前执行,无论方法是否抛出异常,都会执行。
  • 不能阻止目标方法的执行。
  1. 后置通知(After Advice) 也叫最终通知
  • 使用 @After 注解来定义。
  • 在目标方法执行之后执行,无论方法是否抛出异常,都会执行。
  • 通常用于资源清理工作
  • 返回通知(After Returning Advice) 了解
  • 使用 @AfterReturning 注解来定义。
  • 在目标方法成功执行之后执行,即没有抛出异常时执行。
  • 可以获取方法的返回值。
  1. 异常通知(After Advice)了解
  • 使用 @AfterThrowing 注解来定义。
  • 在目标方法抛出异常后执行。
  • 可以获取抛出的异常对象。

注意事项:

  1. 环绕通知需要自己调用joinPoint.proceed()来让原始方法执行,其他通知则不需要。
  2. 环绕通知的返回值必须是Object,来接受原始方法的返回值。
@Slf4j
@Component
@Aspect
public class MyAspect {
   
   

    // 因为示例中的切入点都是一样的,所以不用写多次切入表达式,创建一个方法即可。
    // 此方法也可在其他AOP需要切入点的地方使用。
    @Pointcut("execution(* com.example.service.impl.DeptServiceImpl.*(..))")
    public void pt(){
   
   }

    // 前置通知
    @Before("pt()")
    public void Before(){
   
   
        log.info("before ...");
    }

    // 环绕通知
    @Around("pt()")
    public Object Around(ProceedingJoinPoint joinPoint) throws Throwable {
   
   
        log.info("around after ...");
        // 调用原始方法
        Object proceed = joinPoint.proceed();
        log.info("around after ...");
        return proceed;
    }

    // 后置通知
    @After("pt()")
    public void After(){
   
   
        log.info("after ...");
    }

    // 返回通知
    @AfterReturning("pt()")
    public void Returning(){
   
   
        log.info
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值