Spring AOP详解

目录

一、什么是AOP

二、Spring AOP快速入门

三、AOP核心概念

四、AOP的通知

1.Spring中AOP的通知类型

2.通知执行顺序

3.切入点表达式

4.连接点


一、什么是AOP

        AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,面向切面编程就是面向特定方法编程。使用场景(记录操作日志、权限控制、事务管理)。AOP的优势:减少重复代码、提高开发效率、维护方便、代码无侵入。

        案例某部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务的执行耗时。我们可以在方法开始前,获取方法开始时间,方法结束后获取结束时间,由此计算执行耗时。这个思路是正确的,但是过于繁琐。

        动态代理是面向切面编程最主流的实现。而Spring AOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过动态代理机制,对特定的方法进行编程(功能增强)。

二、Spring AOP快速入门

        导入依赖:在pom.xml中导入AOP的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

        编写AOP程序:针对特定方法根据业务需要进行编程

@Slf4j
@Component//把类交给spring容器进行管理
@Aspect//不是一个普通的类,aop类
public class TimeAspect {
    @Around("execution(* com.example.demo.service.*.*(..))")//切入点表达式
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
//        1.记录开始时间
        long begin =System.currentTimeMillis();
//        2.调用原始方法运行
        Object result=joinPoint.proceed();
//        3.记录结束时间,计算方法执行耗时
        long end=System.currentTimeMillis();
        log.info(joinPoint.getSignature()+"方法执行耗时:{}ms",end-begin);
        return  result;
    }
}

三、AOP核心概念

连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息),可以简单理解为可以被AOP控制的方法。

通知:Advice指定哪些可以重复的逻辑,也就是共性功能(最终被视为一个方法)

切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用(满足条件的连接点)

切面:Aspect,描述通知与切入点对应的关系(通知+切入点)

目标对象:Target,通知所应用的对象

四、AOP的通知

1.Spring中AOP的通知类型

  • @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行(重点

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

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

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

  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

 @Pointcut("execution(* com.example.demo.service.impl.DeptServiceImpl.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info("before ...");
    }

    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();

        //原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了
        log.info("around after ...");
        return result;
    }

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

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

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

@PointCut注解,该注解的作用是将公共的切入点表达式抽取出来,需要用到时引用该切入点表达式即可。需要注意的是:当切入点方法使用private修饰时,仅能在当前切面类中引用该表达式, 当外部其他切面类中也要引用当前类中的切入点表达式,就需要把private改为public,而在引用的时候,具体的语法为:

全类名.方法名(),具体形式如下:

 @Before("com.itheima.aspect.MyAspect1.pt()")

在使用通知时的注意事项:

  • @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行

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

2.通知执行顺序

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

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

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

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

  1. 修改切面类的类名(这种方式非常繁琐、而且不便管理)

  2. 使用Spring提供的@Order注解(注解加在切面类上)

@Order(2)  //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)

3.切入点表达式

切入点表达式:

  • 描述切入点方法的一种表达式

  • 作用:主要用来决定项目中的哪些方法需要加入通知

  • 常见形式:

        execution(……):根据方法的签名来匹配

        execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)

        其中带?的表示可以省略的部分

@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")

可以使用通配符描述切入点

  • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分

  • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数

        @annotation(……) :根据注解匹配

        基于注解的方式来匹配切入点方法。这种方式虽然多一步操作,我们需要自定义一个注解,但是相对来比较灵活。我们需要匹配哪个方法,就在方法上加上对应的注解就可以

实现步骤:

  1. 编写自定义注解

  2. 在业务类要做为连接点的方法上添加自定义注解

4.连接点

        在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等

  • 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型

  • 对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型

        //获取目标类名
        String name = pjp.getTarget().getClass().getName();
        log.info("目标类名:{}",name);

        //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名:{}",methodName);

        //获取方法执行时需要的参数
        Object[] args = pjp.getArgs();
        log.info("目标方法参数:{}", Arrays.toString(args));

        //执行原始方法
        Object returnValue = pjp.proceed();

        "Navigate To Advised Methods" 是一个在许多集成开发环境(IDE)中常见的功能,它允许开发者快速定位到被代理或增强的方法。这个功能通常在处理 AOP(面向切面编程)时非常有用,因为它可以帮助开发者更容易地找到和理解代码中的切面逻辑。

相关推荐

  1. SpringAOP的实现原理

    2024-07-21 13:06:02       46 阅读
  2. 一个简易的SpringAOP实例

    2024-07-21 13:06:02       52 阅读
  3. 浅谈SpringAOP实现原理

    2024-07-21 13:06:02       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 13:06:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 13:06:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 13:06:02       45 阅读
  4. Python语言-面向对象

    2024-07-21 13:06:02       55 阅读

热门阅读

  1. 力扣1834.单线程CPU

    2024-07-21 13:06:02       20 阅读
  2. from lxml import etree 的功能

    2024-07-21 13:06:02       16 阅读
  3. (四)js前端开发中设计模式之工厂方法模式

    2024-07-21 13:06:02       20 阅读
  4. 【web]-反序列化-easy ? not easy

    2024-07-21 13:06:02       18 阅读
  5. php编译安装

    2024-07-21 13:06:02       17 阅读
  6. centos 网卡创建vlan接口

    2024-07-21 13:06:02       15 阅读
  7. 【头歌】 HBase 伪分布式环境搭建 答案

    2024-07-21 13:06:02       14 阅读
  8. ubuntu 挂载硬盘,raspberry pi 树莓派,jetson

    2024-07-21 13:06:02       19 阅读
  9. PCIe总线-RK3588 PCIe驱动设备树介绍(九)

    2024-07-21 13:06:02       13 阅读
  10. 我的创作纪念日——365天

    2024-07-21 13:06:02       17 阅读
  11. 掌握Perl的魔法:深入探索钩子(Hook)机制

    2024-07-21 13:06:02       17 阅读