极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介
仓库地址
Chapter05-SpringBoot中的AOP面向切面编程简介
在上一章中,我们编写了一款基于SpringBoot的书籍信息管理Web应用,实现了对书籍信息的增删查改操作。现在,我们有了一个新的需求:为了方便后台服务监管我们的Web服务的请求耗时,我们需要增强一下对我们的Web应用,希望对每个请求都能够打印一下处理耗时。
基本方式
为了实现这样的需求,我们首先以获取指定ID的书籍信息这个API为例,开始进行编程:
@GetMapping("{id}")
public Book getBookById(@PathVariable("id") String id) {
long currentTimeMillis = System.currentTimeMillis();
try {
// 为了更加明显,我模拟了一个耗时
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Optional<Book> first = this.bookList
.stream()
.filter(b -> b.getId().equals(id))
.findFirst();
System.out.printf("处理耗时:%d ms %n", (System.currentTimeMillis() - currentTimeMillis));
return first.orElse(null);
}
为了模拟一个耗时,我在请求处理的时候对当前处理线程sleep500ms。然后使用对应postman进行请求调用,调用后查看控制台打印:
处理耗时:513 ms
效果还行,但是现在需要对所有的调用都进行日志记录呢?有的同学可能会说,直接开写,一个一个加。牛!此外,我今天的需求是耗时打印,我以后可能需要耗时上传进行预警了,再后来我还希望统计各个API的调用接口,似乎我们愈来愈无法控制这些需求了。每变更一个需求,都需要我们去对每个API进行修改。
还好,我们还有一大杀器:AOP。
AOP
AOP全称Aspect Oriented Programming意为面向切面编程,也叫做面向方法编程,是通过预编译方式和运行期动态代理的方式实现不修改源代码的情况下给程序动态统一添加功能的技术。
流程起点
|
|
---> 切入点1
|
|
---> 切入点2
|
V
流程终点
上图的流程中,我们可以在任何希望的时候切入处理。其好处的就是是的业务逻辑各个部分之间的耦合度降低,提高程序的可重用性。我们可以在完全不侵入业务逻辑代码的情况下就完成各个阶段的切入处理。
核心术语
连接点(JoinPoint)
连接点是在应用执行过程中能够插入切面(Aspect)的一个点。这些点可以是调用方法时、甚至修改一个字段时。它是一个虚拟的概念,例如坐地铁的时候,每一个站都可以下车,那么这每一个站都是一个连接点。假如一个对象中有多个方法,那么这个每一个方法就是一个连接点。
切入点(Pointcut)
切入点是一些特殊的连接点,是具体附加通知的地方。例如坐地铁的时候,具体在某个站下车,那这个站就是切入点。
通知(Advice)
在某个特定的Pointcut切点上需要的执行的动作,如日志记录,权限校验等具体要应用切入点的代码。
五种通知类型:
- 环绕通知:@Around
- 前置通知:@Before
- 返回通知:@After
- 正常返回通知:@AfterReturning
- 异常返回通知:@AfterThrowing
切面(Aspect)
切面是通知和切入点的结合,通知规定了在什么时机干什么事,切入点规定了在什么地方。如“在8点钟在天府广场站下车“ 就是一个切面:时间8点,动作下车就是一个通知;西站就是一个切入点。
对于概念术语还是很抽象,我们直接编写一个切面吧。编写切面之前,首先需要引入相关的依赖。因为切面相关的模块是可选模块,我们在pom中添加如下的依赖:
<dependencies>
<!-- 其他依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
完成依赖导入后,我们编写一个切面类:
/**
* 定义一个日志切面
*/
@Aspect
@Component // 切面不是Bean,需要添加注解
public class LogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
/**
* 定义切点表明要通知的地方
* 这里使用了pointcut expression表达式,具体语法请自行搜索
* 这里解释为包 com.compilemind.guide包以及子包的所有类的所有公共方法
*/
@Pointcut("execution(* com.compilemind.guide..*.*(..))")
public void webLog() {
}
/**
* 指代上面的切点:webLog,并且是调用前执行
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return;
}
HttpServletRequest request = requestAttributes.getRequest();
LOGGER.info("发生请求:" + request.getRequestURI());
LOGGER.info("调用方法:" + joinPoint.getSignature());
}
/**
* 一个关于对应切点的环绕执行的处理
*/
@Around("webLog()")
public Object around(ProceedingJoinPoint joinPoint) {
long currentTimeMillis = System.currentTimeMillis();
// 调用参数
Object[] invokeArgs = joinPoint.getArgs();
// 返回数据
Object returnObj;
try {
// 执行对应的方法,得到结果
returnObj = joinPoint.proceed(invokeArgs);
} catch (Throwable e) {
LOGGER.error("统计某方法执行耗时环绕通知出错", e);
return null;
}
LOGGER.info("处理耗时:{} ms", System.currentTimeMillis() - currentTimeMillis);
return returnObj;
}
}
这个切面由以下几个部分组成:
- 在类上使用
@Aspect注解标记为切面,使用@Component注解标记为组件,由Spring管理; - 编写方法
webLog,并在其方法上添加注解@Pointcut,并按照规则填写切点的位置; - 分别编写由
@Before和@Around注解标记的方法,用以处理对应的切点位置处理前和整个环绕的处理代码。
最后,让我们再次启动程序,进行相关的API调用,可以看到输出:
2021-08-09 16:42:46.494 INFO 18528 --- [nio-8080-exec-2] c.c.guide.chapter04_05.aspect.LogAspect : 发生请求:/books/1
2021-08-09 16:42:46.495 INFO 18528 --- [nio-8080-exec-2] c.c.guide.chapter04_05.aspect.LogAspect : 调用方法:Book com.compilemind.guide.chapter04_05.controller.BookController.getBookById(String)
处理耗时:502 ms
2021-08-09 16:42:47.004 INFO 18528 --- [nio-8080-exec-2] c.c.guide.chapter04_05.aspect.LogAspect : 处理耗时:510 ms
极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介的更多相关文章
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- 基于SpringBoot AOP面向切面编程实现Redis分布式锁
基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...
- 快速高效掌握企业级项目中的Spring面向切面编程应用,外带讲面试技巧
Spring面向切面编程(AOP)是企业级应用的基石,可以这样说,如果大家要升级到高级程序员,这部分的知识必不可少. 这里我们将结合一些具体的案例来讲述这部分的知识,并且还将给出AOP部分的一些常见面 ...
- 浅谈Java中的AOP面向切面的变成和控制反转IOC
https://blog.csdn.net/hi_kevin/article/details/7325554 https://www.cnblogs.com/zedosu/p/6632260.html ...
- 【spring-boot】spring aop 面向切面编程初接触--切点表达式
众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...
- 【spring-boot】spring aop 面向切面编程初接触
众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...
- 在.NET项目中使用PostSharp,实现AOP面向切面编程处理
PostSharp是一种Aspect Oriented Programming 面向切面(或面向方面)的组件框架,适用在.NET开发中,本篇主要介绍Postsharp在.NET开发中的相关知识,以及一 ...
- 利用多态,实现一般处理程序(ashx)中的AOP(切面编程)
本文是对工作中的项目进行代码优化(完善登陆验证的AOP切面编程)时,所遇到的各种解决方案思考过程. 项目背景:由ashx+nvelocity构建的简单B/S问卷系统,现需要优化登录验证环节(时隔若干个 ...
- AOP面向切面编程在Android中的使用
GitHub地址(欢迎下载完整Demo) https://github.com/ganchuanpu/AOPDemo 项目需求描述 我想类似于这样的个人中心的界面,大家都不会陌生吧.那几个有箭头的地方 ...
随机推荐
- Java finally语句到底是在return之前还是之后执行
看过网上关于Java中异常捕获机制try-catch-finally块中的finally语句是不是一定会被执行的讨论也有很多. 首先明确一点,下面两种情况finally肯定是不执行的: 1). ret ...
- linux centos 设置笔记本合盖不待机
1.设置笔记本合盖不待机 打开配置文件 vi /etc/systemd/logind.conf 将 HandleLidSwitch 变量前的注释 # 去掉 修改 HandleLidSwitch 变量参 ...
- js日期处理多少/月/天以前
var date = new Date(); var year = date.getFullYear(); var month = (date.getMonth() + 1) > 10 ? da ...
- 三大操作系统对比使用之·MacOSX
时间:2018-11-13 整理:byzqy 本篇是一篇个人对Mac系统使用习惯和应用推荐的分享,在此记录,以便后续使用查询! 打开终端: command+空格,调出"聚焦搜索(Spotli ...
- 华为分析X HUAWEI Ads,上线深度转化事件回传功能,让ROI 看得见!
华为分析X HUAWEI Ads,上线深度转化事件回传功能,让ROI 看得见! 随着移动应用生态的流量成本攀升.行业竞争加剧,越来越多的广告商希望通过精准投放来获取更高质量的深度转化用户,比如二手车. ...
- NOIP模拟22「d·e·f」
T1:d 枚举. 现在都不敢随便打枚举了. 实际上我们只关注最后留下的矩阵中最小的长与宽即可. 所以我们将所有矩阵按a的降序排列. 从第\(n-m\)个开始枚举. 因为你最多拿 ...
- docker一分钟搭建nginx服务器
运行nginx服务 拉取: docker pull nginx:1.17.9 运行: docker run -d --name nginx -P 80:80 nginx:1.17.9 -d表示在后台启 ...
- Linux从头学12:读完这篇【特权级】文章,你就比别人更“精通”操作系统!
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...
- 使用ECS和OSS搭建个人网盘
体验简介 本场景将提供一台配置了Centos 7.7版本的ECS实例(云服务器)和对象存储OSS实例.通过本教程的操作,您可以基于ECS和OSS快速搭建一个个人网盘. 体验此场景后,可以掌握的知识有: ...
- webgl 图像处理 加速计算
webgl 图像处理 webgl 不仅仅可以用来进行图形可视化, 它还能进行图像处理 图像处理1---数据传输 webgl 进行图形处理的第一步: 传输数据到 GPU 下图为传输点数据到 GPU 并进 ...