SpringBoot核心框架之AOP详解
一、AOP基础
1.1 AOP概述
- AOP:Aspect Oriented Programming(面向切面编程,面向方面编程),其实就是面向特定方法编程。
- 场景:项目部分功能运行较慢,定位执行耗时较长的业务方法,此时就需要统计每一个业务的执行耗时。
- 思路:给每个方法在开始前写一个开始计时的逻辑,在方法结束后写一个计时结束的逻辑,然后相减得到运行时间。
思路是没问题的,但是有个问题,一个项目是有很多方法的,如果挨个增加逻辑代码,会相当繁琐,造成代码的臃肿,所以可以使用AOP编程,将计时提出成一个这样的模板:
- 获取方法运行开始时间
- 运行原始方法
- 获取方法运行结束时间,计算执行耗时
原始方法就是我们需要计算时间的方法,并且可以对原始方法进行增强,其实这个技术就是用到了我们在Java基础部分学习的动态代理技术。
实现:动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要是通过底层的动态代理机制,对特点的方法进行编程。
1.2 AOP快速入门
统计各个业务层方法执行耗时
-
导入依赖:在pom.xml中导入AOP的依赖。
org.springframework.boot spring-boot-starter-aop -
编写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;
}
} -
查看结果
这样我们就完成了,一个AOP的小例子,但是AOP的功能远不能这些,他还有更多的实用的功能。比如:记录操作日志:可以记录谁什么时间操作了什么方法,传了什么参数,返回值是什么都可以很方便的实现。还有比如权限控制,事务管理等等。
我们来总结一下AOP的优势
- 代码无侵入
- 减少重复代码
- 提高开发效率
- 维护方便
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代码即可。