Spring中最重要的两个部分

1.IOC 控制反转
        2.AOP面向切面编程

博主之前有一篇文章是关于SpringIOC的理解:关于SpringIOC的理解有需要的小伙伴可以自行跳转。

下面,我们今天来一起学习下SpringAOP相关的知识点。SpringAOP的英文全称是——(Aspect-Oriented Programming)面向切片编程,切片的理解大家可以想象一下切片面包,一个面包整体就是我们的项目,而把面包从业务的角度切成一片一片的,这些切片就是我们的业务。我们来举一个例子,比如下面这张图:

在我们没有使用SpringAOP时,我们想要实现一个电商项目的日志追踪功能,我们需要在我们的每个业务层中都去添加这一功能相关的代码,繁琐而且缠绕,比如登录Service中本来只需要处理登录业务相关的代码逻辑,但是却不得不加入输出打印日志相关的代码。但是使用了AOP面向切面编程之后:

我们只需要在controller 和 service中间切上那么一刀,把我们的日志追踪功能添加进去,然后通知Spring,并标注切入点。我们就可以实现业务之间的解耦,让每一块单独的业务只关心自己当前模块的相关业务。代码不再缠绕。总结一下:

  • 面向切面的编程(AOP)实现了横切关注的模块化, 横切关注的代码都在一个地方

  • 关注点分离: 如 日志关注点从业务代码中独立出来, 业务模块不用再关心日志问题.

    解决了:

  • 代码缠绕, 关注点耦合

  • 代码分散, 同样的关注分散在各个模块

那么我们如何去使用SpringAOP中的功能呢?

SpringAOP使用步骤
1.导入依赖

我们在maven中导入SpringAOP的相关依赖,

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

2.创建切面组件, 封装横切关注点代码

通过@Aspect注解标注这个是切面组件

3.标注通知 @Before()

就是通知Spring在什么之前执行以下相关代码,如上代码段中就是告诉Spring,要在personServiceImpl这个业务实现类中的所有方法前执行,如果需要标注具体方法,可以通过@Pointcut统一管理切入点。

4.标注切入点 "bean(personServiceImpl)"

5.在切面中获取用户调用的方法: 连接点(JoinPoint)

@Aspect //表示这就是切面
@Component//组件注解
public class DemoAspect {private static Logger logger LoggerFactory.getLogger(DemoAspect.class);/*** 在 personServiceImpl bean 的方法之前执行 log()* @Before 称为 通知* bean(personServiceImpl) 称为 切入点* JoinPoint: 连接点, 就是当前方法, 连接到的目标方法*/@Before("bean(personServiceImpl)")public void log(JoinPoint joinPoint){// Signature: 签名, 这里是方法签名// 方法签名: 方法名 + 参数列表Signature signature = joinPoint.getSignature();logger.debug("方法前记录下用户行为:{} 时间执行了 {}",LocalDateTime.now(), signature);}}

  • 连接点(JoinPoint)

    • 程序执行过程中的一个点,例如方法的调用,或抛出异常
    • 就是 AOP 切面的插入点
  • 切入点 Pointcut

    • 选择一个或多个连接点的表达式, 告诉AOP, 选择那些切入位置.
    • bean(personServiceImpl), 选择personServiceImpl Bean 全部方法
  • Advice 通知

    • 在选择的每个连接点执行的代码
    • 在连接点的执行代码位置:
      • @Before 正在切入点之前执行
      • @After 正在切入点之后, 无论是否有异常都执行
      • @AfterThrowing 正在切入点出现异常以后执行
      • @AfterReturning 正在切入点正在实行结束以后执行
      • @Around 环绕通知
  • 切面 Aspect

    • 一个囊括了切入点和Advice的模块
    • 是一个类, 包含全部的 切入点, 通知等
  • 编织(织入)

    • 将切面与主要代码进行结合的技术, Spring 底层的代码, 采用动态代理技术, 将Aspect嵌入的目标代码

@AfterReturning 中获取返回值

@AfterThrowing中获取异常信息

/*** 获取 切入点方法的返回值*/
@AfterReturning(value = "bean(personServiceImpl)", returning = "result")
public void test2(JoinPoint joinPoint, Object result){Signature signature = joinPoint.getSignature();logger.debug("方法正常结束记录下用户行为:{} 时间执行了 {}, 返回值:{}",LocalDateTime.now(), signature, result);
}/*** 获取 切入点方法发生的异常*/
@AfterThrowing(value = "bean(personServiceImpl)", throwing = "e")
public void test3(JoinPoint joinPoint, Exception e){Signature signature = joinPoint.getSignature();logger.debug("方法异常结束记录下用户行为:{} 时间执行了 {} 异常: {}",LocalDateTime.now(), signature, e.getMessage());
}

@Pointcut 统一管理切入点

  • 使用@Pointcut定义一个切入点表达式, 将切入点表达式绑定到一个 方法名称
  • 其他通知, 只需要绑定方法名称即可
  • 优势: 当切入点表达式复杂时候, 可以统一管理, 避免反复书写
@Aspect //切面组件, 注解, 来自 aspectj
@Component
public class DemoAspect {private static Logger logger = LoggerFactory.getLogger(DemoAspect.class);/***  @Pointcut 统一管理切入点* - 定义一个切入点表达式* - 将切入点表达式绑定到一个 名称(方法名)* - 其他通知, 只需要绑定方法名称即可*/@Pointcut("bean(personServiceImpl)")public void personService(){}/*** 在 personServiceImpl bean 的方法之前执行 log()* @Before 称为 通知* bean(personServiceImpl) 称为 切入点* JoinPoint: 连接点, 就是当前方法, 连接到的目标方法*/@Before("personService()")public void log(JoinPoint joinPoint){// Signature: 签名, 这里是方法签名// 方法签名: 方法名 + 参数列表Signature signature = joinPoint.getSignature();logger.debug("方法前记录下用户行为:{} 时间执行了 {}",LocalDateTime.now(), signature);}@After("personService()")public void test(JoinPoint joinPoint){Signature signature = joinPoint.getSignature();logger.debug("方法后记录下用户行为:{} 时间执行了 {}",LocalDateTime.now(), signature);}/*** 获取 切入点方法的返回值*/@AfterReturning(value = "personService()", returning = "result")public void test2(JoinPoint joinPoint, Object result){Signature signature = joinPoint.getSignature();logger.debug("方法正常结束记录下用户行为:{} 时间执行了 {}, 返回值:{}",LocalDateTime.now(), signature, result);}/*** 获取 切入点方法发生的异常*/@AfterThrowing(value = "personService()", throwing = "e")public void test3(JoinPoint joinPoint, Exception e){Signature signature = joinPoint.getSignature();logger.debug("方法异常结束记录下用户行为:{} 时间执行了 {} 异常: {}",LocalDateTime.now(), signature, e.getMessage());}
}

@Around 环绕通知, 强大的万能通知!

在连接点(JoinPoint)环绕执行

@Around 可以替代: @Before @After 等全部通知

@Around("personService()")
public Object demo(ProceedingJoinPoint joinPoint) throws Throwable{Signature signature = joinPoint.getSignature();logger.debug("在连接点{}之前", signature);Object value = joinPoint.proceed();  //执行目标连接点方法logger.debug("在连接点{}之后", signature);// 狸猫换太子: 替换返回值的演示// Around 通知中, 可以对返回值进行加工处理, 实现丰富的行为// if (value instanceof List){//      value = new ArrayList<>();// }return value;
}

使用注意事项:

  • @Around 的连接点类型 ProceedingJoinPoint, 表示被执行是方法

  • joinPoint.proceed() 表示执行连接点方法

    • 如果不执行, 就意味着连接点方法被放弃! 这种行为可能是一个有害行为

      • 一般都是要执行
    • joinPoint.proceed() 的返回值是连接方法的返回值, 原则上要作为当前方法的返回值

      • 可以在AOP方法中对这个返回值进行加工处理, 不过这个可能是危险行为!
    • joinPoint.proceed() 的异常就是连接点方法执行异常, 如果进行拦截处理, 就意味着影响异常处理流程.

  • @Around 的功能强大, 可以处理返回值, 可以处理异常, 可以在切入点方法前嵌入代码, 可以在切入点方法之后嵌入代码.

  • 请谨慎使用 @Around

SpringAOP初识——初学者向相关推荐

  1. 《C#初学者指南》一第1章 初识C#

    本节书摘来异步社区<C#初学者指南>一书中的第1章,作者: [加拿大]Jayden Ky 译者: 李强 , 吴戈 责编: 陈冀康,更多章节内容可以访问云栖社区"异步社区" ...

  2. 【Java】初识泛型(带你从初学者角度切入,通俗易懂,速进)

    2022.11.29 西安 初雪- 泛型在Java中十分重要,也比较难理解,本文旨在让初学者有大概的理解. 一.什么是泛型 1.1 引入泛型 一般的类和方法,只能使用具体的类型: 要么是基本类型,要么 ...

  3. oc中怎么写c语言函数,献给Objective-C的初学者--入门篇(一)初识OC

    写这篇文章的目的: 笔者其实也是初学者,所以笔者理解想要入门又不知道怎么办的同道中人那种心情:同时也是笔者对所学的做一个回顾.好了废话不多说,下面开始正题. OC是一门面向对象的语言 那么什么是面向对 ...

  4. 初识jQuery(适合初学者哟.........)

     您要知道!! jQuery是目前使用最广泛的javascript函数库.据统计,全世界排名前100万的网站,有46%使用jQuery,远远超过其他库. 微软公司甚至把jQuery作为他们的官方库.对 ...

  5. 初学者对python的认识_Python初学者列表,python,初识

    1.认识列表 列表可以放入所有我们目前学习过的数据类型,甚至包括列表 2.有关列表的方法.内置函数(设列表的名称为list) 向列表中添加元素: append():list.append(要添加的元素 ...

  6. 初识JAVA(二)(送给Java和安卓初学者)----常见错误

    博主接着上篇的来讲哦,以后的更新中,博主会出一些练习题,有兴趣的可以做做然后吧代码粘贴到下面,大家可以一起研究学习,一起进步,本篇文章主要讲的是: 一.常见错误 二.连接上篇一起的训练 无论是什么方向 ...

  7. vba 编辑combobox内容_初识Visual Basic编辑器并建立一段简单的代码

    大家好,从今日开始我正式推出"VBA之EXCEL应用"教程,这个教程是面向初学人员的教程,教程一共三册,十七个章节,从简单的录制宏实现一直讲到窗体的搭建,都是我们在利用EXCEL工 ...

  8. yolo-mask的损失函数l包含三部分_【AI初识境】深度学习中常用的损失函数有哪些?...

    这是专栏<AI初识境>的第11篇文章.所谓初识,就是对相关技术有基本了解,掌握了基本的使用方法. 今天来说说深度学习中常见的损失函数(loss),覆盖分类,回归任务以及生成对抗网络,有了目 ...

  9. 「AI初识境」深度学习中常用的损失函数有哪些?

    https://www.toutiao.com/a6695152940425937411/ 这是专栏<AI初识境>的第11篇文章.所谓初识,就是对相关技术有基本了解,掌握了基本的使用方法. ...

最新文章

  1. 摘录来自mysql 5.1的手册 关于mysql的事务处理和锁定语句
  2. 数据库开发——MySQL——索引原理
  3. 华为云UGO正式公测:4大核心优势破解异构数据库迁移难题
  4. 一加将于10月14日推出新款Buds系列真无线耳塞
  5. TCP三次握手连接和TCP四次挥手及大量TIME_WAIT解决方法:
  6. Angucomplete —— AngularJS 自动完成输入框
  7. chrome webstore
  8. nginx connect() to (13: Permission denied) while connecting
  9. 华为将发布定制款“鸿蒙字体”,可以免费商用
  10. ip-guard网页浏览放开微信二维码和QQ截图
  11. 智能红绿灯自动控制系统分析
  12. nginx location正则匹配规则
  13. shell之BASH_SOURCE
  14. 【数据库】用户sa登录失败,错误:18456
  15. 表示背景色彩的html是,[html颜色代码]HTML语言中,设置背景颜色的代码是?
  16. 2022-12-24 三阶魔方完整教程和口诀速记,二级魔方教程
  17. dw建站404问题,dw 404
  18. 【Python】科研论文绘图实操干货汇总,11类Matplotlib图表,含代码
  19. re python 引擎_python 详解re模块
  20. 数仓基于表级别的数据血缘分析

热门文章

  1. a算法TSP旅行商java_A*算法解决旅行商问题
  2. Linux反弹shell方式总结
  3. 两位数四则混合运算考试题
  4. java编程自学教程(超详细版)
  5. 程序设计中常用的解题策略 pdf电子书
  6. 【矩阵论】Hermite二次型(1)
  7. uicolor swift_Swift中的UIColor
  8. CCF-CSP真题《202209-2 何以包邮?》思路+python满分题解
  9. 从QQ同步助手上导出的短信文件*.csv中读取短信,并运用在Qt程序中
  10. LBP特征原理与人脸检测