当前位置:网站首页 > 技术博客 > 正文

springboot整合aop



一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 21 天,点击查看活动详情

日积月累,水滴石穿 😄

AOP 为 Aspect Oriented Programming 的缩写,翻译为面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗理解就是在不修改源代码的情况下,在主干功能里面添加新的功能。

  • Advisor:切面,也可以称为 ,由 切点(pointCut)和 建议(advice)组成。
  • Advice:单词意思是建议,不过国内程序员一般称为通知。建议切面在何时执行以及如何执行增强处理。说的直白点就是代理逻辑。通知分为如下几种:
    • Before :前置通知,在连接点前调用。如果抛出异常则不会流转到连接点。
    • After :后置通知,在连接点后调用,不管连接点是否执行正常、异常都会执行的通知。
    • AfterReturning:返回通知,在连接点执行正常并返回后调用,执行正常也就是说在执行过程中没有发生异常。
    • AfterThrowing:异常通知,当连接点执行发生异常时调用。
    • Around:环绕通知,连接点执行的前后可以执行自定义代码。
  • Join point:连接点,在 中一个连接点就是一个方法
  • PointCut:切点,一系列连接点的集合,可以通过表达式找到一系列的连接点。
  • Target object:目标对象。被一个或多个切面建议的对象,也就是被代理对象。
  • AOP proxy:代理对象。由 AOP 框架创建的对象,使用的是JDK 动态代理或 CGLIB 代理。
  • Weaving:织入,就是将代理逻辑添加到对目标类具体连接点上,并创建代理对象的过程。

Spring 框架是基于 AspectJ 实现 AOP 操作!但各位需要知道, AspectJ 并不是 Spring 的组成部分,它是一个独立的框架,Spring AOP引入了对 AspectJ 的支持,也建议使用 AspectJ 来开发 AOP。

使用 Spring 实现 AOP 方式有两种,分别如下:

  • XML 配置文件实现
  • 注解实现 先来看一下不使用 AOP 的代码!
 
 

类中就一个注解。

 
 

测试代码,运行结果如下:

 

过了一段时间,项目经理跟你聊天。。。

  • 项目经理:我想在 方法中加一个方法执行开始时间和方法执行结束时间吧,但是有个要求不能改动原逻辑!你有什么好注意。
  • 你:稍作考虑,我们可以使用 Spring AOP 进行实现。
  • 项目经理:怎么使用 AOP 呢?
  • 你:我所了解到的方式有两种,分别是 XML 配置文件实现注解实现
  • 项目经理:嗯,看来你胸有成竹了,那这任务就交给你了,别让我失望哦!
  • 你:嗯好的,我先写个 demo 给您过目一下。

既然要使用 Spring AOP,那先在  文件中引入相关依赖:

 

Spring AOP 的依赖就不需要再次加入了,中有 Spring AOP 的依赖。

XML方式的 AOP 配置有许多的标签,在这里进行介绍一下。

元素备注aop:aspectj-autoproxy启用 @AspectJ 注解支持,与 @EnableAspectJAutoProxy效果一致aop:config最外层的 AOP 元素,大多数的其他AOP元素(切面、切点、通知)需要写在 aop:config 元素内。aop:advisor定义 AOP 通知器,通知器跟切面一样,也包括通知和切点。aop:aspect定义一个切面,aop:aspect 元素内可以定义通知类型!aop:pointcut定义切点aop:before前置通知,在连接点执行前调用。aop:after后置通知,在连接点执行后调用。不管目标方法是否发生异常。aop:after-returning返回通知,在连接点执行正常并返回后调用。aop:after-throwing异常通知,当连接点执行发生异常时调用。aop:around环绕通知,连接点执行之前和之后都可以执行额外代码。
  • ProductController
 
  • ProductAspect
 
 
 

测试代码,运行结果如下:

 

接下来就对该方法进行 AOP 增强!

  • 1、增加 aop 命名空间
 
  • 2、增加如下配置
 

测试代码,运行结果如下:

 

xml 方式可以对重复使用的切点表达式进行提取,使用标签。

 
  • 当 元素作为 元素的子元素定义时,表示它可被多个切面所共享。
  • 当 元素作为 元素的子元素时,表示该切入点只对当前切面有效。

上面展示了 定义切面的使用方式。下面介绍标签的使用方式。,定义 AOP 通知器,通知器跟切面一样,也包括通知和切点。但需要注意一点:定义切面时,可以引用普通 bean,而定义时,引用的通知必须实现 Advice 接口。

1、创建名为 的类,实现 , 两个接口!

 
    • MethodBeforeAdvice:前置通知,在连接点执行前调用。
    • AfterReturningAdvice:返回通知,在连接点执行正常并返回后调用。
  • 2、在Spring配置文件中增加如下代码:
 
  • 3、启动结果如下:
 

为了防止与上面的代码冲突,在其 包下,所有类重新进行创建!

 

在配置类中新增注解,代表开启 @AspectJ 注解支持。

也可以使用 xml 方式开启 AOP 方式,如以下示例所示:

 
 
 

类上, 使用注解表示它将作为一个 Spring Bean 被容器管理,使用注解  表示它是一个切面。

类中有两个方法 、,分别使用 、注解进行标注。代表在目标方法执行前、目标方法执行后执行。具体用法下面介绍。

两个方法都有一个类型为 的参数,这个参数是 提供的,可以用来获取到方法信息。比如:目标方法参数、目标对象等等。这个参数是非必选的。

 声明了切点,也就是 ,表明在该切面的切点是这个类中的方法,就是一个连接点。 对于的具体用法下面会简单介绍介绍。

 

测试代码,运行结果如下:

 

完美达到项目经理的要求!

注解方式也有 5 种通知类型,分别如下:

  • Before :前置通知,在连接点执行前调用。
属性备注value绑定切入点表达式。可以直接设置切入点表达式,也可以设置切入点声明
  • After :后置通知,在连接点执行后调用。不管目标方法是否发生异常。 | 属性 | 备注 | | --- | --- | |value| 绑定切入点表达式。可以直接设置切入点表达式,也可以设置切入点声明|
  • AfterReturning:返回通知,在连接点执行正常并返回后调用,执行正常也就是说在执行过程中没有发生异常。 | 属性 | 备注 | | --- | --- | |value| 绑定切入点表达式。可以直接设置切入点表达式,也可以设置切入点声明| |pointcut| 跟 value 效果一致,但优先级高于 value| |returning| 将目标方法的返回值绑定到指定的参数名称|
  • AfterThrowing:异常通知,当连接点执行发生异常时调用。 | 属性 | 备注 | | --- | --- | |value| 绑定切入点表达式。可以直接设置切入点表达式,也可以设置切入点声明| |pointcut| 跟 value 效果一致,但优先级高于 value| |throwing| 将目标方法发生的异常绑定到指定的参数名称|
  • Around:环绕通知,连接点执行之前和之后都可以执行额外代码。 | 属性 | 备注 | | --- | --- | |value| 绑定切入点表达式。可以直接设置切入点表达式,也可以设置切入点声明|

那如何使用呢?在上述例子中已经使用到和 两种通知,接下来将其他类型的通知补全,然后进行测试,观察它们的执行顺序。

 

测试代码,运行结果如下:

 

可以发现执行顺序为 。 注意不同的 Spring 版本可能会有差异。比如 5.0.8.RELEASE 和 5.3.17。

环绕通知是五种通知中最复杂、也是最强大的一种,需要传入类型为  参数,这个参数也只能加在环绕通知上。有了这个参数就可以干其他逻辑,比如:获得当前方法的参数、方法、目标对象。

并且还需要显示调用  的  方法。 如果没调用该方法,那执行结果如下 :

 
  • 可以发现并没有将 、、这几句话打印出来,也就是说,如果不调用  方法,则不会执行 前置通知 和 目标方法逻辑、返回通知、后置通知。当然正常来说,也不会如此使用!

根据打印的日志还可以发现最终方法返回值为变为了 。但是在环绕通知里还是有返回值的,这是为什么呢?

因为被标注的方法是 void,那么就需要给 的方法设置返回参数,

 

测试代码,运行结果如下:

 
  • 上面的例子并没有执行异常通知,那异常通知需要怎么才能被执行呢?需要当连接点执行发生异常时调用。那就在 方法中抛一个异常吧!
 

测试代码,运行结果如下:

 

OK,达到目的,返回通知并没有被执行,并且异常通知有执行。

上面我们定义了五种通知,但是五种通知的切入点表达式都是一致的。是不是觉得代码重复率挺高的。对于这种频繁出现的相同的表达式,可以使用 注解声明切点表达式,抽取公用切点表达式,然后在各种通知中进行使用,具体使用如下:

 

测试代码,运行结果如下:

 

切入点表达式有什么作用呢?寻找连接点。

上面只用到了其中一种表达式:。

语法结构如下:

结构中带符号的匹配式都是可选的,也就是说必写的只有三个:

  1. 返回类型匹配
  2. 方法名匹配
  3. 参数匹配

还支持通配符

  1. :匹配所有字符
  2. :匹配多个包或者多个参数
  3. :表示类及其子类
  4. :运算符

可能比较难以理解,下面举几个例子:

  • 1、对 类里面的 方法进行增强 结构:
  • 2、对 类里面的所有方法进行增强 结构:
  • 3、对 包中的所有类、所有方法进行增强 结构:
  • 4、对 类里面的 方法或者 进行增强

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。

版权声明


相关文章:

  • idea如何单元测试2024-12-02 14:01:01
  • zd03 3(2)2024-12-02 14:01:01
  • c++文本文件输入输出2024-12-02 14:01:01
  • 安全测试软件有哪些2024-12-02 14:01:01
  • 数据结构时间复杂度空间复杂度汇总2024-12-02 14:01:01
  • ddos压力测试网页端2024-12-02 14:01:01
  • mysql函数大全以及举例2024-12-02 14:01:01
  • sp.socrcv指令说明2024-12-02 14:01:01
  • springboot h2数据库2024-12-02 14:01:01
  • 备忘录功能介绍2024-12-02 14:01:01